855 lines
44 KiB
C#
855 lines
44 KiB
C#
using BaseOUDAL;
|
|
using CsvHelper;
|
|
using CsvHelper.Configuration;
|
|
using ICSharpCode.SharpZipLib.Zip;
|
|
using System.Data;
|
|
using YLErp.Commons;
|
|
using YLErp.DBModels.Helpers;
|
|
using YLErp.Modules.ClientModule;
|
|
using YLErp.Modules.TradeModule;
|
|
using YLErp.Office.ExcelModule;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.Modules.EodModule.QueryModule
|
|
{
|
|
/// <summary>
|
|
/// 日终持仓导出服务
|
|
/// 暂时用于兴证数据接口导出
|
|
/// </summary>
|
|
public class EodTradePositionExportService : YLBaseService
|
|
{
|
|
public EodTradePositionExportService(OptUserInfo optUser) : base(optUser)
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 查询场外期权持仓列表
|
|
/// </summary>
|
|
public void SearchOptionTradeListForExport(DateTime valueDate
|
|
, out List<EodOptionPositionExportFields> listOption
|
|
, out List<EodPayOffSwapPositionExportFields> listSwap)
|
|
{
|
|
listSwap = null;
|
|
listOption = null;
|
|
|
|
var IsPVRounded = PS.Config.IsPVRounded;
|
|
|
|
valueDate = valueDate.Date;
|
|
|
|
var query = from et in DbContext.eod_trade
|
|
join etp in DbContext.eod_trade_position on et.TradeId equals etp.TradeId
|
|
join etr in DbContext.eod_trade_risk on et.TradeId equals etr.TradeId
|
|
where et.ValueDate == valueDate && etp.ValueDate == valueDate && etr.ValueDate == valueDate
|
|
&& et.TradeId > 0 && etp.TradeId > 0 && etr.TradeId > 0
|
|
&& et.TradeType != "结构化交易" && et.ClientId > 0
|
|
select new
|
|
{
|
|
et.TradeId,
|
|
et.TradeJson,
|
|
etp.Amount,
|
|
etp.Pv,
|
|
PositionPv = IsPVRounded ? etp.RoundedPv : etp.Pv,
|
|
PositionPnl = IsPVRounded ? etp.RoundedPositionPnL : etp.PositionPnL,
|
|
etr.Vol
|
|
};
|
|
|
|
//因为query还在读取中,所以不要用同一个dbcontext
|
|
var extendService = new TradeExtendService(OptUser);
|
|
|
|
foreach (var item in query)
|
|
{
|
|
var td = TradeHelper2.Deserialize(item.TradeJson);
|
|
if (td == null)
|
|
{
|
|
td = DbContext.trade.Find(item.TradeId);
|
|
}
|
|
if (td == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
extendService.SetTradeExtend(new[] { td }, true);
|
|
|
|
if (td.TradeType == "收益互换")
|
|
{
|
|
var f = GetEodPayOffSwapPostionFields(td, item.Amount, item.PositionPnl, item.PositionPv);
|
|
if (listSwap == null)
|
|
{
|
|
listSwap = new List<EodPayOffSwapPositionExportFields>();
|
|
}
|
|
listSwap.Add(f);
|
|
}
|
|
else if (td.TradeType == "远期")
|
|
{
|
|
|
|
}
|
|
else
|
|
{
|
|
var f = GetEodOptionPostionFields(td, item.Amount, item.PositionPnl, item.PositionPv, item.Vol);
|
|
if (listOption == null)
|
|
{
|
|
listOption = new List<EodOptionPositionExportFields>();
|
|
}
|
|
listOption.Add(f);
|
|
}
|
|
}
|
|
}
|
|
|
|
//场外期权
|
|
private EodOptionPositionExportFields GetEodOptionPostionFields(trade td, double PositionTradeAmount, double PositionPnl, double PositionPv, double PositionVol)
|
|
{
|
|
var isMoneyness = td.IsMoneynessOption == "是";
|
|
var isPremiumRate = td.IsUsePremiumRate == true;
|
|
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
|
|
var volFormat = PS.Config.ErpElement.VolMoreAccurate ? "P2" : "P4";
|
|
|
|
var f = new EodOptionPositionExportFields
|
|
{
|
|
TradeNumber = td.TradeNumber,
|
|
AssetBookName = td.AssetBookName,
|
|
TraderName = td.TraderName,
|
|
ClientName = td.ClientName,
|
|
StructureType = td.TradeType,
|
|
ExerciseMode = td.ExerciseModeCn,
|
|
CallPut = td.CallPut,
|
|
TradeDate = td.TradeDate.OtcFormatDate(),
|
|
ExerciseDate = td.ExerciseDate.OtcFormatDate(),
|
|
SettlementDate = td.SettlementDate.OtcFormatDate(),
|
|
TradeSide = td.BuySell,
|
|
UnderlyingCode = td.UnderlyingCode,
|
|
UnderlyingName = underlying?.UnderlyingName,
|
|
InitSpotPrice = td.SpotPrice.OtcFormatUmPrice(),
|
|
Strike = td.Strike.OtcFormatUmPrice(isMoneyness),
|
|
IsMoneynessOption = isMoneyness ? "是" : "否",
|
|
Premium = isPremiumRate ? td.PremiumRate.OtcFormat(OtcFormatFlag.premiumRateP) : td.TradeSinglePrice.OtcFormat(OtcFormatFlag.tradeSinglePrice),
|
|
IsUsePremiumRate = isPremiumRate ? "是" : "否",
|
|
InitialMargin = td.InitialMargin.OtcFormatMoney(),
|
|
TradeAmount = td.OriginalNotional.OtcFormatNotional(),
|
|
TradePrice = td.TradePrice.OtcFormatMoney(),
|
|
StockEqvNotional = td.OriginalStockEqvNotional.OtcFormat(OtcFormatFlag.StockEqvNotional),
|
|
StockEqvNotionalReal = td.StockEqvNotionalReal.OtcFormat(OtcFormatFlag.StockEqvNotional),
|
|
IsAnnualized = td.IsAnnualized ? "是" : "否",
|
|
AnnualizeFactor = td.AnnualizeFactor?.ToString("F8"),
|
|
PrincipalRate = td.PrincipalRate.OtcFormatPercent(),
|
|
ParticipationRate = td.ParticipationRate.OtcFormatPercent(),
|
|
NoRiskRate = td.NoRiskRate.OtcFormatPercent(),
|
|
DividendRate = td.DividendRate.OtcFormatPercent(),
|
|
TradeOpenVolatility = td.TradeOpenVolatility?.ToString(volFormat),
|
|
TradeCloseVolatility = td.TradeCloseVolatility?.ToString(volFormat),
|
|
NumOfSmoothingDays = td.NumOfSmoothingDays?.ToString(),
|
|
Comments = td.Comments,
|
|
|
|
PositionPnl = Convert.ToDouble(PositionPnl).OtcFormatMoney(),
|
|
PositionPv = Convert.ToDouble(PositionPv).OtcFormatMoney(),
|
|
PositionTradeAmount = PositionTradeAmount.OtcFormatNotional(),
|
|
PositionVol = PositionVol.ToString(volFormat)
|
|
};
|
|
|
|
f.ClientNumber = ClientDataQueryService.GetClient(td.ClientId)?.Number;
|
|
|
|
switch (f.StructureType)
|
|
{
|
|
case "亚式期权":
|
|
if (td.trade_asian_option != null)
|
|
{
|
|
var ext = td.trade_asian_option;
|
|
f.AsianAveragingPeriodStartDate = ext.AveragingPeriodStartDate.OtcFormatDate();
|
|
f.AsianPayoffType = ext.PayoffTypeCn;
|
|
f.AsianStrikeType = ext.StrikeTypeCn;
|
|
f.AsianStrikeGearingFactor = ext.StrikeGearingFactor.OtcFormatPercent();
|
|
}
|
|
break;
|
|
case "障碍期权":
|
|
if (td.trade_barrier_option != null)
|
|
{
|
|
var ext = td.trade_barrier_option;
|
|
f.BarrierType = ext.BarrierType;
|
|
f.BarrierPrice = ext.BarrierPrice.OtcFormatUmPrice(isMoneyness);
|
|
f.BarrierPriceHigh = ext.UpperBarrierPrice.OtcFormatUmPrice(isMoneyness);
|
|
f.BarrierShift = ext.BarrierShift.OtcFormatUmPrice();
|
|
f.BarrierRebate = OtcFormatHelper.FormatPremium(td.IsUsePremiumRate, ext.RebateRate, ext.Rebate);
|
|
f.BarrierRebateType = ext.RebateTypeCn;
|
|
f.BarrierDiscrete = ext.Discrete;
|
|
f.BarrierKnockInOutStatus = ext.KnockInOutStatus;
|
|
f.BarrierKnockInOutDate = ext.KnockInOutDate.OtcFormatDate();
|
|
}
|
|
break;
|
|
case "双鲨期权":
|
|
if (td.trade_double_sharkfin_option != null)
|
|
{
|
|
var ext = td.trade_double_sharkfin_option;
|
|
f.DbsharkBarrierLow = ext.BarrierLow.OtcFormatUmPrice(isMoneyness);
|
|
f.DbsharkBarrierHigh = ext.BarrierHigh.OtcFormatUmPrice(isMoneyness);
|
|
f.DbsharkStrikeHigh = ext.StrikeHigh.OtcFormatUmPrice(isMoneyness);
|
|
f.DbsharkCallParticipationRate = ext.CallParticipationRate.OtcFormatPercent();
|
|
f.DbsharkPutParticipationRate = ext.PutParticipationRate.OtcFormatPercent();
|
|
f.DbsharkRebate = OtcFormatHelper.FormatPremium(td.IsUsePremiumRate, ext.RebateRate, ext.Rebate);
|
|
f.DbsharkRebateHigh = OtcFormatHelper.FormatPremium(td.IsUsePremiumRate, ext.RebateHighRate, ext.RebateHigh);
|
|
f.DbsharkRebateType = TradeHelper.GetRebateTypeCn(ext.RebateType);
|
|
f.DbsharkDiscrete = ext.Discrete;
|
|
|
|
}
|
|
break;
|
|
case "二元期权":
|
|
if (td.trade_binary_option != null)
|
|
{
|
|
var ext = td.trade_binary_option;
|
|
f.BinaryPayoffType = ext.PayoffType;
|
|
f.BinaryUpperBarrier = ext.UpperBarrier.OtcFormatUmPrice(isMoneyness);
|
|
f.BinaryCashOrNothingAmount = OtcFormatHelper.FormatPremium(td.IsUsePremiumRate, ext.CashOrNothingAmountRate, ext.CashOrNothingAmount);
|
|
f.BinaryCashOrNothingAmountHigh = OtcFormatHelper.FormatPremium(td.IsUsePremiumRate, ext.CashOrNothingAmountHighRate, ext.CashOrNothingAmountHigh);
|
|
f.BinaryMonitorType = ext.MonitorType;
|
|
f.BinaryRebateType = TradeHelper.GetRebateTypeCn(ext.RebateType);
|
|
}
|
|
break;
|
|
case "区间累积期权":
|
|
if (td.trade_rangeaccrual != null)
|
|
{
|
|
var ext = td.trade_rangeaccrual;
|
|
f.RangeAccrualLowerRange = ext.LowerRange.OtcFormatUmPrice(isMoneyness);
|
|
f.RangeAccrualUpperRange = ext.UpperRange.OtcFormatUmPrice(isMoneyness);
|
|
f.RangeAccrualBonusRate = ext.BonusRate.OtcFormatPercent(4);
|
|
f.CallPut = string.Empty;
|
|
}
|
|
break;
|
|
case "气囊结构":
|
|
if (td.trade_airbag != null)
|
|
{
|
|
var ext = td.trade_airbag;
|
|
f.AirbagBarrier = ext.Barrier.OtcFormatUmPrice(isMoneyness);
|
|
f.AirbagIsDiscrete = ext.IsDiscreteMonitored ? "是" : "否";
|
|
f.AirbagKIParticipationRate = ext.KIParticipationRate.OtcFormatPercent();
|
|
f.AirbagHasPayoffLimit = ext.HasPayoffLimit ? "是" : "否";
|
|
f.AirbagHighStrike = ext.HighStrike.OtcFormatUmPrice(isMoneyness);
|
|
f.CallPut = string.Empty;
|
|
}
|
|
break;
|
|
case "收益增强结构":
|
|
if (td.trade_underlying_enhance != null)
|
|
{
|
|
f.CallPut = string.Empty;
|
|
f.AnnualizedEnhanceRate = td.trade_underlying_enhance.AnnualizedEnhanceRate.OtcFormatPercent(4);
|
|
}
|
|
break;
|
|
case "凤凰期权":
|
|
if (td.trade_autocall != null)
|
|
{
|
|
var ext = td.trade_autocall;
|
|
f.AutocallIsFixedCoupon = ext.IsFixedCoupon ? "否" : "是";
|
|
f.AutocallCoupon = ext.Coupon.OtcFormatPercent();
|
|
f.AutocallCouponBarrier = ext.CouponBarrier.OtcFormatUmPrice(isMoneyness);
|
|
f.AutocallCouponPayType = ext.CouponPayTypeDesc();
|
|
f.AutocallKOBarrier = ext.KOBarrier.OtcFormatUmPrice(isMoneyness);
|
|
f.AutocallKIBarrier = ext.KIBarrier.OtcFormatUmPrice(isMoneyness);
|
|
f.AutocallIncludeCouponAfterKI = ext.IncludeCouponAfterKI ? "是" : "否";
|
|
f.AutocallKIPayoffType = ext.KIPayoffTypeDesc();
|
|
f.AutocallKIStrike1 = ext.SpreadStrike1.OtcFormatUmPrice(isMoneyness);
|
|
if (ext.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption)
|
|
{
|
|
f.AutocallKIStrike2 = ext.SpreadStrike.OtcFormatUmPrice(isMoneyness);
|
|
}
|
|
var KOObservationDates = ext.KOObservationDates ?? string.Empty;
|
|
var index = KOObservationDates.IndexOf(';');
|
|
f.KOObservationDates = index > 0 ? ext.KOObservationDates.Substring(0, index) : KOObservationDates;
|
|
f.KIObservationDates = ext.ObservationDates;
|
|
f.IsAnnualized = ext.IsAnnualized2 ? "是" : "否";
|
|
}
|
|
break;
|
|
case "雪球期权":
|
|
if (td.trade_snowball != null)
|
|
{
|
|
var ext = td.trade_snowball;
|
|
f.SnowballKOBarrier = ext.KOBarrier.OtcFormatUmPrice(isMoneyness);
|
|
switch (ext.KOPayoffType)
|
|
{
|
|
case KOPayoffTypeEnum.Rebate:
|
|
f.SnowballKOPayoffType = "票息补偿";
|
|
f.SnowballIsFixedCoupon = ext.IsFixedCoupon ? "否" : "是";
|
|
f.SnowballKORebate = ext.KORebate.OtcFormatPercent();
|
|
f.SnowballAnnualizedPremiumRate = ext.AnnualizedPremiumRate.OtcFormatPercent();
|
|
f.SnowballKOObservationSettleDates = ext.KOObservationSettleDates;
|
|
break;
|
|
case KOPayoffTypeEnum.ToOption:
|
|
f.SnowballKOPayoffType = KOPayoffTypeEnumHelper.GetDesc(ext.KOPayoffType, td.CallPut);
|
|
f.SnowballKOStrike1 = ext.SpreadStrikeAtKO1.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
case KOPayoffTypeEnum.ToSpreadOption:
|
|
f.SnowballKOPayoffType = KOPayoffTypeEnumHelper.GetDesc(ext.KOPayoffType, td.CallPut);
|
|
f.SnowballKOStrike2 = ext.SpreadStrikeAtKO.OtcFormatUmPrice(isMoneyness);
|
|
f.SnowballKOStrike1 = ext.SpreadStrikeAtKO1.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
default:
|
|
f.SnowballKOPayoffType = ext.KOPayoffType.ToString();
|
|
break;
|
|
}
|
|
f.SnowballKORebateType = RebateTypeEnumHelper.GetDesc(ext.KORebateType);
|
|
f.SnowballKIBarrier = ext.KIBarrier.OtcFormatUmPrice(isMoneyness);
|
|
switch (ext.KIPayoffType)
|
|
{
|
|
case KIPayoffTypeEnum.None:
|
|
f.SnowballKIPayoffType = "无";
|
|
break;
|
|
case KIPayoffTypeEnum.ToPutOption:
|
|
f.SnowballKIPayoffType = "敲入转看跌";
|
|
f.SnowballKIStrike1 = ext.SpreadStrikeAtMaturity1.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
case KIPayoffTypeEnum.ToPutSpreadOption:
|
|
f.SnowballKIPayoffType = "敲入转熊市价差";
|
|
f.SnowballKIStrike2 = ext.SpreadStrikeAtMaturity.OtcFormatUmPrice(isMoneyness);
|
|
f.SnowballKIStrike1 = ext.SpreadStrikeAtMaturity1.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
case KIPayoffTypeEnum.ToCallOption:
|
|
f.SnowballKIPayoffType = "敲入转看涨";
|
|
f.SnowballKIStrike1 = ext.SpreadStrikeAtMaturity1.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
case KIPayoffTypeEnum.ToCallSpreadOption:
|
|
f.SnowballKIPayoffType = "敲入转牛市价差";
|
|
f.SnowballKIStrike2 = ext.SpreadStrikeAtMaturity.OtcFormatUmPrice(isMoneyness);
|
|
f.SnowballKIStrike1 = ext.SpreadStrikeAtMaturity1.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
default:
|
|
f.SnowballKIPayoffType = ext.KIPayoffType.ToString();
|
|
break;
|
|
}
|
|
f.SnowballNoKICoupon = ext.Coupon.OtcFormatPercent();
|
|
var KOObservationDates = ext.KOObservationDates ?? string.Empty;
|
|
var index = KOObservationDates.IndexOf(';');
|
|
f.KOObservationDates = index > 0 ? ext.KOObservationDates.Substring(0, index) : KOObservationDates;
|
|
f.KIObservationDates = ext.ObservationDates;
|
|
f.IsAnnualized = ext.IsAnnualized2 ? "是" : "否";
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (td.TradeType == "凤凰期权" || td.TradeType == "雪球期权")
|
|
{
|
|
f.CallPut = f.ExerciseMode = string.Empty;
|
|
td.MetaDic.TryGetValue(nameof(OtcOptionTradeFull.AnnualizeFactor2), out var metaValue);
|
|
f.AnnualizeFactor = metaValue;
|
|
}
|
|
else
|
|
{
|
|
td.MetaDic.TryGetValue(nameof(OtcOptionTradeFull.AnnualizeFactor), out var metaValue);
|
|
f.AnnualizeFactor = metaValue;
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
//收益互换
|
|
private EodPayOffSwapPositionExportFields GetEodPayOffSwapPostionFields(trade td, double PositionTradeAmount, double PositionPnl, double PositionPv)
|
|
{
|
|
var swap = td.trade_swap ?? new trade_swap();
|
|
|
|
var f = new EodPayOffSwapPositionExportFields
|
|
{
|
|
TradeNumber = td.TradeNumber,
|
|
AssetBookName = td.AssetBookName,
|
|
TraderName = td.TraderName,
|
|
ClientName = td.ClientName,
|
|
TradeDate = td.TradeDate.OtcFormatDate(),
|
|
ExerciseDate = td.ExerciseDate.OtcFormatDate(),
|
|
StockEqvNotional = td.OriginalStockEqvNotional.OtcFormat(OtcFormatFlag.StockEqvNotional),
|
|
Comments = td.Comments,
|
|
|
|
GetFixedProfit = swap.GetFixedProfit.OtcFormatMoney(),
|
|
GetLongShort = swap.GetLongShort,
|
|
GetMarginRate = swap.GetMarginRate.OtcFormatFlex(minDecimals: 0, percent: true),
|
|
GetTradePrice = swap.GetTradePrice.OtcFormatMoney(),
|
|
GetUnderlyingCode = swap.GetUnderlyingCode,
|
|
GetSpotPrice = swap.GetSpotPrice.OtcFormatUmPrice(),
|
|
IsGetFloatingProfit = swap.IsGetFloatingProfit ? "是" : "否",
|
|
|
|
IsPayFloatingProfit = swap.IsPayFloatingProfit ? "是" : "否",
|
|
PayFixedProfit = swap.PayFixedProfit.OtcFormatMoney(),
|
|
PayLongShort = swap.PayLongShort,
|
|
PayMarginRate = swap.PayMarginRate.OtcFormatMoney(),
|
|
PaySpotPrice = swap.PaySpotPrice.OtcFormatUmPrice(),
|
|
PayTradePrice = swap.PayTradePrice.OtcFormatMoney(),
|
|
PayUnderlyingCode = swap.PayUnderlyingCode,
|
|
|
|
PositionPnl = Convert.ToDouble(PositionPnl).OtcFormatMoney(),
|
|
PositionPv = Convert.ToDouble(PositionPv).OtcFormatMoney(),
|
|
PositionStockEqvNotional = PositionTradeAmount.OtcFormat(OtcFormatFlag.StockEqvNotional)
|
|
};
|
|
|
|
f.ClientNumber = ClientDataQueryService.GetClient(td.ClientId)?.Number;
|
|
|
|
return f;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 查询场内期权持仓列表
|
|
/// </summary>
|
|
public IEnumerable<EodExOptionPositionExportFields> SearchExOptionTradeListForExport(DateTime valueDate)
|
|
{
|
|
var IsPVRounded = PS.Config.IsPVRounded;
|
|
var umSource = DataCacheProvider.GetUnderlyingDataSource();
|
|
var exOptionSource = DataCacheProvider.GetExchangeListOptionDataSource();
|
|
var volFormat = PS.Config.ErpElement.VolMoreAccurate ? "P2" : "P4";
|
|
|
|
valueDate = valueDate.Date;
|
|
|
|
var query = from etp in DbContext.eod_trade_position
|
|
join etr in DbContext.eod_trade_risk on etp.TradeId equals etr.TradeId
|
|
where etp.ValueDate == valueDate && etr.ValueDate == valueDate
|
|
&& etp.TradeType == "场内期权"
|
|
select new
|
|
{
|
|
etp.UnderlyingCode,
|
|
etp.ExchangeOptionCode,
|
|
etp.Amount,
|
|
etp.PositionType,
|
|
PositionPv = IsPVRounded ? etp.RoundedPv : etp.Pv,
|
|
PositionPnl = IsPVRounded ? etp.RoundedPositionPnL : etp.PositionPnL,
|
|
etr.Vol
|
|
};
|
|
|
|
var list = new List<EodExOptionPositionExportFields>();
|
|
|
|
foreach (var item in query)
|
|
{
|
|
var exoption = exOptionSource.GetData(item.ExchangeOptionCode);
|
|
var f = new EodExOptionPositionExportFields
|
|
{
|
|
OptionCode = item.ExchangeOptionCode,
|
|
ExerciseMode = exoption?.ExerciseMode,
|
|
Strike = (exoption?.Strike)?.ToString("F4"),
|
|
UnderlyingCode = item.UnderlyingCode,
|
|
|
|
PositionType = item.PositionType,
|
|
PositionPnl = Convert.ToDouble(item.PositionPnl).OtcFormatMoney(),
|
|
PositionPv = Convert.ToDouble(item.PositionPv).OtcFormatMoney(),
|
|
PositionTradeAmount = item.Amount.OtcFormatNotional(),
|
|
PositionVol = item.Vol.ToString(volFormat)
|
|
};
|
|
|
|
list.Add(f);
|
|
}
|
|
return list;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 导出兴证数据中心需要的文件
|
|
/// </summary>
|
|
public byte[] ExportXingZhengZipFile(DateTime valueDate, out string zipFileName, IEnumerable<int> clienIds = null)
|
|
{
|
|
valueDate = valueDate.Date;
|
|
|
|
if (QdpCalendarHelper.GetNonHoliday(valueDate) != valueDate)
|
|
{
|
|
throw new ServiceException($"所选日期'{valueDate:yyyy-MM-dd}'不是交易日!");
|
|
}
|
|
|
|
if (!DbContext.eodStatus.Any(n => n.ValueDate == valueDate && n.Status == "已收盘"))
|
|
{
|
|
throw new ServiceException($"所选日期'{valueDate:yyyy-MM-dd}'未收盘!");
|
|
}
|
|
|
|
SearchOptionTradeListForExport(valueDate, out var listOption, out var listSwap);
|
|
|
|
var listExOption = SearchExOptionTradeListForExport(valueDate);
|
|
|
|
var dateStr = valueDate.ToString("yyyyMMdd");
|
|
|
|
zipFileName = $"ylotc_position_{dateStr}.zip";
|
|
|
|
var clients = DbContextFactory.GetClientDbContext(UserInfo).client
|
|
.Where(d => d.ProcessStatus == "已开户" || d.ProcessStatus == "已休眠" || d.ProcessStatus == "已销户")
|
|
.Select(n => new InnerClientInfo { id = n.id, ClientNumber = n.Number, ClientName = n.Name, LicenseCode = n.LicenseCode, ClientType = n.ClientType }).ToArray();
|
|
#region 新增客户筛选 tw
|
|
if (clienIds != null)
|
|
{
|
|
clients = clients.Where(l => clienIds.Contains(l.id)).ToArray();
|
|
}
|
|
#endregion
|
|
using (var yldb = DbContextFactory.GetYLDbContext())
|
|
{
|
|
var sumQuery = from t in yldb.trade
|
|
where t.ValidState != ConsGlobal.InValid && t.IsGroup != 2
|
|
&& (t.TradeType != "结构化交易" || t.IsGroup == 1)
|
|
group t by t.ClientId into g
|
|
select new
|
|
{
|
|
clientId = g.Key,
|
|
sum = g.Sum(n => n.OriginalStockEqvNotional ?? 0)
|
|
};
|
|
|
|
var sumDic = sumQuery.ToDictionary(n => n.clientId, m => m.sum);
|
|
|
|
foreach (var c in clients)
|
|
{
|
|
if (sumDic.TryGetValue(c.id, out var sum))
|
|
{
|
|
c.StockEqvNotional = sum.ToString("F4");
|
|
}
|
|
}
|
|
}
|
|
|
|
using (var ms = new MemoryStream())
|
|
using (var outStream = new ZipOutputStream(ms))
|
|
using (var writer = new StreamWriter(outStream))
|
|
{
|
|
var csvConfig = new CsvConfiguration(System.Globalization.CultureInfo.InvariantCulture)
|
|
{
|
|
LeaveOpen = true,
|
|
Delimiter = "$#$"
|
|
};
|
|
outStream.PutNextEntry(new ZipEntry($"ylotc_position_option_{dateStr}.csv"));
|
|
using (var csv = new CsvWriter(writer, csvConfig))
|
|
{
|
|
csv.WriteRecords(listOption ?? Enumerable.Empty<EodOptionPositionExportFields>());
|
|
}
|
|
writer.Flush();
|
|
|
|
outStream.PutNextEntry(new ZipEntry($"ylotc_position_exoption_{dateStr}.csv"));
|
|
using (var csv = new CsvWriter(writer, csvConfig))
|
|
{
|
|
csv.WriteRecords(listExOption ?? Enumerable.Empty<EodExOptionPositionExportFields>());
|
|
}
|
|
writer.Flush();
|
|
|
|
outStream.PutNextEntry(new ZipEntry($"ylotc_position_payoffswap_{dateStr}.csv"));
|
|
using (var csv = new CsvWriter(writer, csvConfig))
|
|
{
|
|
csv.WriteRecords(listSwap ?? Enumerable.Empty<EodPayOffSwapPositionExportFields>());
|
|
}
|
|
writer.Flush();
|
|
|
|
outStream.PutNextEntry(new ZipEntry($"ylotc_client_{dateStr}.csv"));
|
|
using (var csv = new CsvWriter(writer, csvConfig))
|
|
{
|
|
csv.WriteRecords(clients);
|
|
}
|
|
writer.Flush();
|
|
|
|
writer.Close();
|
|
return ms.ToArray();
|
|
}
|
|
|
|
}
|
|
public byte[] GetClient()
|
|
{
|
|
var templateFile = OtcAppContext.MapPath("~/App_Docs/导出模板/国投客户数据采集.xlsx");
|
|
using (var baseDb = new ClientDBContext())
|
|
{
|
|
//处理客户不属于 内部客户 n.IsInsided!=1
|
|
var ClientList = baseDb.client.Where(n => n.ProcessStatus == "已开户"&&n.IsInsided!=1).Select(x =>
|
|
new ClientInfo
|
|
{
|
|
ClientType = x.ClientType == "自然人" ? "个人" : x.ClientType,
|
|
ClientName = x.Name,
|
|
ClientTypeMemo = x.ClientType == "机构" ? "机构全称" : x.ClientType == "自然人" ? "" : "产品全称",
|
|
AdminFullName = x.ClientType == "产品" ? x.AdminFullName : "",
|
|
LicenseType = x.ClientType == "机构" ? "统一社会信用代码" : x.ClientType == "自然人" ? "居民身份证" : "产品编号",
|
|
AdminFullNameMome = x.ClientType == "产品" ? "产品管理人全称" : "",
|
|
IdentificationNumber = x.ClientType == "机构" ? x.LicenseCode : x.ClientType == "自然人" ? x.IdentificationNumber : x.ProductNumber,
|
|
AdminFullNameLicenseType = x.ClientType == "机构" ? "" : x.ClientType == "自然人" ? "" : "统一社会信用代码",
|
|
AdminRegisteredNum = x.ClientType == "产品" ? x.LicenseCode : "",
|
|
MainProtocolCode = x.MainProtocolCode
|
|
});
|
|
var buffer = ExcelGenerator.UseTemplateGenerator(templateFile).AddVariable(new { list = ClientList }).GenerateBytes();
|
|
return buffer;
|
|
}
|
|
}
|
|
public byte[] GetEodPosition(Model.EodPositionRisksReq req)
|
|
{
|
|
var templateFile = OtcAppContext.MapPath("~/App_Docs/导出模板/国投数据采集.xlsx");
|
|
using (var baseDb = new ClientDBContext())
|
|
{
|
|
req.ValueDate = req.ValueDate;
|
|
req.EodSettlePriceMode = "收盘价";
|
|
req.IsOnlyExport = false;
|
|
req.IsParentTrade = false;
|
|
req.needSettleData = false;
|
|
req.VolType = "持仓";
|
|
//处理客户不属于 内部客户
|
|
req.ClientIds = baseDb.client.Where(n => n.IsInsided != 1).Select(l => l.id).ToList();
|
|
|
|
var result = new EodPositionRisksQueryService(UserInfo).SearchList(req);
|
|
var responEodPositions = new List<ResponEodPosition>();
|
|
foreach (var item in result.rows)
|
|
{
|
|
var responEodPosition = new ResponEodPosition();
|
|
var td = DbContext.trade.FirstOrDefault(l => l.id == item.id);
|
|
responEodPosition.bookName = item.AssetBookName;
|
|
responEodPosition.tradeId = item.TradeNumber;
|
|
responEodPosition.positionId = item.trade?.AssetId;
|
|
responEodPosition.underlyerInstrumentId = item.UnderlyingCode;
|
|
responEodPosition.underlyerMultiplier = GetunderlyerMultiplier(item.UnderlyingCode);
|
|
responEodPosition.productType = item.TradeType;
|
|
responEodPosition.initialNumber = item.TradeOriginalAmount;
|
|
responEodPosition.unwindNumber = td?.UnWindNotional;
|
|
responEodPosition.number = item.Notional;
|
|
responEodPosition.premium = item.TradePrice;
|
|
responEodPosition.marketValue = item.RoundedPV;
|
|
responEodPosition.pnl = item.dailyPnl;
|
|
responEodPosition.delta = item.Delta;
|
|
responEodPosition.deltaCash = item.DeltaCash;
|
|
responEodPosition.gamma = item.Gamma;
|
|
responEodPosition.gammaCash = item.GammaCash;
|
|
responEodPosition.vega = item.Vega;
|
|
responEodPosition.theta = item.Theta;
|
|
responEodPosition.rho = item.Rho;
|
|
responEodPosition.effectiveDate = td?.TradeDate;
|
|
responEodPosition.expirationDate = td?.ExerciseDate;
|
|
responEodPosition.message = "";
|
|
responEodPosition.pricingEnvironment = "";
|
|
responEodPosition.r = item.RiskFreeRate;
|
|
responEodPosition.q = item.DividendRate;
|
|
responEodPosition.vol = item.CurrentVolatility;
|
|
responEodPosition.listedOption = 0;//!
|
|
responEodPosition.price = item.UnderlyingPrice;
|
|
responEodPosition.notional = td?.StockEqvNotionalReal;
|
|
responEodPosition.initialNotional = item.StockEqvNotional;
|
|
responEodPosition.initialMargin = item.Margin;
|
|
responEodPosition.maintenanceMargin = td?.InitialMargin;
|
|
|
|
responEodPosition.initialVol = item.CurrentVolatility;
|
|
responEodPosition.masterAgreementId = GetmasterAgreement(item.ClientNumber);
|
|
responEodPosition.direction = td?.BuySell;
|
|
if (td != null)
|
|
{
|
|
responEodPosition.initialQ = GetinitialQ(item.id, req.ValueDate);
|
|
responEodPosition.initialR = GetinitialR(item.id, req.ValueDate);
|
|
responEodPosition.term = QdpModule.QdpCalendarHelper.AllBizDays(Convert.ToDateTime(td.TradeDate), Convert.ToDateTime(td.ExerciseDate)).Count;
|
|
var strike = DbContext.trade_double_sharkfin_option.FirstOrDefault(l => l.TradeId == item.id);
|
|
responEodPosition.highStrike = strike?.StrikeHigh;
|
|
responEodPosition.lowStrike = strike?.StrikeLow;
|
|
}
|
|
|
|
responEodPosition.settlementDate = td?.SettlementDate;//!
|
|
responEodPosition.tradeStatus = item.TradeStatus;
|
|
responEodPosition.lcmEventType = item.TradeStatus;
|
|
responEodPosition.initialSpot = td?.SpotPrice;
|
|
|
|
responEodPosition.highBarrier = item.RebateHigh;
|
|
responEodPosition.lowBarrier = item.Rebate;
|
|
responEodPosition.participationRates = item.ParticipationRate;
|
|
responEodPosition.rebate = item.Rebate;
|
|
responEodPosition.annualized = td?.IsAnnualized;
|
|
responEodPosition.specifiedPrice = td?.SettlementType == SettlementTypeEnum.ClosePrice ? "收盘价" : "结算价";
|
|
responEodPosition.frontPremium = item.TradeAmount;
|
|
responEodPosition.minimumPremium = td?.PrincipalRateWrite;
|
|
responEodPosition.daysInYear = item.InitialSpotPrice;//?
|
|
responEodPosition.initialPricingValue = item.TradeSinglePrice;
|
|
responEodPosition.initialUnderlyerPrice = td?.UnderlyingPrice;
|
|
responEodPosition.portfolioNames = item.TradeType;
|
|
responEodPosition.trader = td?.TraderName;
|
|
responEodPosition.tradeConfirmId = item.ContractCode;
|
|
responEodPosition.underlyerPrice = item.UnderlyingPrice;
|
|
responEodPosition.callput = item.trade?.CallPut;
|
|
responEodPositions.Add(responEodPosition);
|
|
}
|
|
var buffer = ExcelGenerator.UseTemplateGenerator(templateFile).AddVariable(new { list2 = responEodPositions }).GenerateBytes();
|
|
return buffer;
|
|
}
|
|
}
|
|
/// <summary>
|
|
/// 获取开仓无风险利率
|
|
/// </summary>
|
|
public double? GetinitialQ(int tdId, DateTime dateTime)
|
|
{
|
|
return DbContext.TradeHisData.Where(l => l.TradeId == tdId && l.ValueDate == dateTime && l.ValueType == "NoRiskRate").FirstOrDefault()?.Value;
|
|
}
|
|
/// <summary>
|
|
/// 获取开仓分红率
|
|
/// </summary>
|
|
public double? GetinitialR(int tdId, DateTime dateTime)
|
|
{
|
|
return DbContext.TradeHisData.Where(l => l.TradeId == tdId && l.ValueDate == dateTime && l.ValueType == "DividendRate").FirstOrDefault()?.Value;
|
|
}
|
|
/// <summary>
|
|
/// 获取 合约乘数
|
|
/// </summary>
|
|
/// <param name="UnderlyingCode"></param>
|
|
/// <returns></returns>
|
|
public double? GetunderlyerMultiplier(string UnderlyingCode)
|
|
{
|
|
var underlyerMultiplier = DataCacheProvider.GetUnderlyingDataSource().GetData(UnderlyingCode).ContractSize;
|
|
return underlyerMultiplier;
|
|
}
|
|
/// <summary>
|
|
/// 获取sac主协议编号
|
|
/// </summary>
|
|
/// <param name="ClientNumber"></param>
|
|
/// <returns></returns>
|
|
public string GetmasterAgreement(string ClientNumber)
|
|
{
|
|
var clientdb = new ClientDBContext();
|
|
if (string.IsNullOrEmpty(ClientNumber))
|
|
{
|
|
return "";
|
|
}
|
|
return clientdb.client.First(l => l.Number == ClientNumber).MainProtocolCode;
|
|
}
|
|
// {{item.positionId}} {{item.underlyerInstrumentId}} {{item.underlyerInstrumentIds}} {{item.underlyerMultiplier}} {{item.underlyerMultipliers}}
|
|
// {{item.productType}} {{item.initialNumber}} {{item.initialNumbers}} {{item.unwindNumber}} {{item.unwindNumbers}} {{item.number}} {{item.numbers}}
|
|
// {{item.premium}} {{item.unwindAmount}} {{item.marketValue}} {{item.pnl}} {{item.delta}} {{item.deltas}} {{item.deltaCash}} {{item.deltaCashes}}
|
|
// {{item.deltaDecay}} {{item.deltaDecays}} {{item.deltaWithDecay}} {{item.deltaWithDecays}} {{item.gamma}} {{item.gammas}} {{item.gammaCash}}
|
|
// {{item.gammaCashes}} {{item.vega}} {{item.vegas}} {{item.theta}} {{item.rho}} {{item.tradeDate}} {{item.effectiveDate}} {{item.expirationDate}}
|
|
// {{item.message}} {{item.createdAt}} {{item.pricingEnvironment}} {{item.r}} {{item.q}} {{item.qs}} {{item.vol}} {{item.vols}} {{item.listedOption}}
|
|
// {{item.price}} {{item.correlation}} {{item.notional}} {{item.initialNotional}} {{item.initialMargin}} {{item.initialQ}} {{item.initialR}} {{item.initialVol}}
|
|
// {{item.maintenanceMargin}} {{item.masterAgreementId}} {{item.direction}} {{item.term}} {{item.settlementDate}} {{item.tradeStatus}} {{item.lcmEventType}}
|
|
// {{item.initialSpot}} {{item.initialSpots}} {{item.highStrike}} {{item.lowStrike}} {{item.highBarrier}} {{item.lowBarrier}} {{item.participationRates}}
|
|
// {{item.rebate}} {{item.annualized}} {{item.specifiedPrice}} {{item.frontPremium}} {{item.minimumPremium}} {{item.daysInYear}} {{item.initialPricingValue}}
|
|
// {{item.initialUnderlyerPrice}} {{item.initialPnl}} {{item.initialStdDelta}} {{item.initialDelta}} {{item.initialDeltaCash}} {{item.initialGamma}} {{item.initialGammaCash}} {{item.initialVega}} {{item.initialTheta}} {{item.initialRhoR}} {{item.initialStdGamma}} {{item.tradeCategory}} {{item.portfolioNames}} {{item.trader}} {{item.tradeConfirmId}} {{item.regulationAssetClass}} {{item.regulationAssetSubClass}} {{item.underlyerPrice}}
|
|
class ResponEodPosition
|
|
{
|
|
public string bookName { get; set; }
|
|
public string tradeId { get; set; }
|
|
public int? positionId { get; set; }
|
|
public string underlyerInstrumentId { get; set; }
|
|
public string underlyerInstrumentIds { get; set; }
|
|
public double? underlyerMultiplier { get; set; }
|
|
public string underlyerMultipliers { get; set; }
|
|
public string productType { get; set; }
|
|
public double? initialNumber { get; set; }
|
|
public double? initialNumbers { get; set; }
|
|
public double? unwindNumber { get; set; }
|
|
public double? unwindNumbers { get; set; }
|
|
public double? number { get; set; }
|
|
public double? numbers { get; set; }
|
|
public double? premium { get; set; }
|
|
public double? unwindAmount { get; set; }
|
|
public double? marketValue { get; set; }
|
|
public double? pnl { get; set; }
|
|
public double? delta { get; set; }
|
|
public double? deltas { get; set; }
|
|
public double? deltaCash { get; set; }
|
|
public double? deltaCashes { get; set; }
|
|
public double? deltaDecay { get; set; }
|
|
public double? deltaDecays { get; set; }
|
|
public double? deltaWithDecay { get; set; }
|
|
public double? deltaWithDecays { get; set; }
|
|
public double? gamma { get; set; }
|
|
public double? gammas { get; set; }
|
|
public double? gammaCash { get; set; }
|
|
public double? gammaCashes { get; set; }
|
|
public double? vega { get; set; }
|
|
public double? vegas { get; set; }
|
|
public double? theta { get; set; }
|
|
public double? rho { get; set; }
|
|
public string tradeDate { get; set; }
|
|
public DateTime? effectiveDate { get; set; }
|
|
public DateTime? expirationDate { get; set; }
|
|
public string message { get; set; }
|
|
public string createdAt { get; set; }
|
|
public string pricingEnvironment { get; set; }
|
|
public double? r { get; set; }
|
|
public double? q { get; set; }
|
|
public double? qs { get; set; }
|
|
public double? vol { get; set; }
|
|
public double? vols { get; set; }
|
|
public double? listedOption { get; set; }
|
|
public double? price { get; set; }
|
|
public double? correlation { get; set; }
|
|
public double? notional { get; set; }
|
|
public double? initialNotional { get; set; }
|
|
public double? initialMargin { get; set; }
|
|
public double? initialQ { get; set; }
|
|
public double? initialR { get; set; }
|
|
public double? initialVol { get; set; }
|
|
public double? maintenanceMargin { get; set; }
|
|
public string masterAgreementId { get; set; }
|
|
public string direction { get; set; }
|
|
public int term { get; set; }
|
|
public DateTime? settlementDate { get; set; }
|
|
public string tradeStatus { get; set; }
|
|
public string lcmEventType { get; set; }
|
|
public double? initialSpot { get; set; }
|
|
public double? initialSpots { get; set; }
|
|
public double? highStrike { get; set; }
|
|
public double? lowStrike { get; set; }
|
|
public double? highBarrier { get; set; }
|
|
public double? lowBarrier { get; set; }
|
|
public double? participationRates { get; set; }
|
|
public double? rebate { get; set; }
|
|
public bool? annualized { get; set; }
|
|
public string specifiedPrice { get; set; }
|
|
public double? frontPremium { get; set; }
|
|
public double? minimumPremium { get; set; }
|
|
public double? daysInYear { get; set; }
|
|
public double? initialPricingValue { get; set; }
|
|
public double? initialUnderlyerPrice { get; set; }
|
|
public double? initialPnl { get; set; }
|
|
public double? initialStdDelta { get; set; }
|
|
public double? initialDelta { get; set; }
|
|
public double? initialDeltaCash { get; set; }
|
|
public double? initialGamma { get; set; }
|
|
public double? initialGammaCash { get; set; }
|
|
public double? initialVega { get; set; }
|
|
public double? initialTheta { get; set; }
|
|
public double? initialRhoR { get; set; }
|
|
public double? initialStdGamma { get; set; }
|
|
public double? tradeCategory { get; set; }
|
|
public string portfolioNames { get; set; }
|
|
public string trader { get; set; }
|
|
public string tradeConfirmId { get; set; }
|
|
public string regulationAssetClass { get; set; }
|
|
public string regulationAssetSubClass { get; set; }
|
|
public double? underlyerPrice { get; set; }
|
|
public string callput { get; set; }
|
|
|
|
}
|
|
class ClientInfo
|
|
{
|
|
/// <summary>
|
|
/// 客户类型
|
|
/// </summary>
|
|
public string ClientType { get; set; }
|
|
/// <summary>
|
|
/// 客户名称
|
|
/// </summary>
|
|
public string ClientName { get; set; }
|
|
/// <summary>
|
|
/// 客户类型备注 机构全称,产品全称,居民身份证
|
|
/// </summary>
|
|
public string ClientTypeMemo { get; set; }
|
|
/// <summary>
|
|
/// 证件类型
|
|
/// </summary>
|
|
public string LicenseType { get; set; }
|
|
/// <summary>
|
|
/// 证件号
|
|
/// </summary>
|
|
public string IdentificationNumber { get; set; }
|
|
/// <summary>
|
|
/// 产品管理人
|
|
/// </summary>
|
|
public string AdminFullName { get; set; }
|
|
/// <summary>
|
|
/// 主协议编号
|
|
/// </summary>
|
|
public string MainProtocolCode { get; set; }
|
|
/// <summary>
|
|
/// 证件类型备注 产品管理人全称
|
|
/// </summary>
|
|
public string AdminFullNameMome { get; set; }
|
|
/// <summary>
|
|
/// 产品管理人证件类型
|
|
/// </summary>
|
|
public string AdminFullNameLicenseType { get; set; }
|
|
/// <summary>
|
|
/// 产品管理人证件号
|
|
/// </summary>
|
|
public string AdminRegisteredNum { get; set; }
|
|
}
|
|
class InnerClientInfo
|
|
{
|
|
internal int id { get; set; }
|
|
|
|
public string ClientNumber { get; set; }
|
|
|
|
public string ClientName { get; set; }
|
|
|
|
public string LicenseCode { get; set; }
|
|
|
|
public string ClientType { get; set; }
|
|
|
|
public string StockEqvNotional { get; set; }
|
|
}
|
|
}
|
|
}
|