746 lines
34 KiB
C#
746 lines
34 KiB
C#
using System.Data;
|
|
using YLErp.Commons;
|
|
using YLErp.DBModels.Helpers;
|
|
using YLErp.Models;
|
|
using YLErp.Modules.DataProviderModule;
|
|
using YLErp.Modules.TradeModule;
|
|
|
|
namespace YLErp.Modules.EodModule.QueryModule
|
|
{
|
|
/// <summary>
|
|
/// 日终清算服务
|
|
/// </summary>
|
|
public class EodTradePositionApiService : YLBaseService<EodSettleInfoQueryContext>
|
|
{
|
|
public EodTradePositionApiService(EodSettleInfoQueryContext context) : base(context)
|
|
{
|
|
|
|
}
|
|
|
|
/// <summary>
|
|
/// 查询场外期权持仓列表
|
|
/// </summary>
|
|
public EodTradePositionResult GetEodPositions(EodSettleInfoRequest req, List<int> clientIdsOfInside = null)
|
|
{
|
|
var valueDate = req.ValueDate;
|
|
var result = new EodTradePositionResult
|
|
{
|
|
SwapPositions = new List<EodPayOffSwapPositionField>(),
|
|
OptionPositions = new List<EodOptionPositionField>(),
|
|
ForwardPositions = new List<EodForwardPositionField>()
|
|
};
|
|
|
|
var IsPVRounded = PS.Config.IsPVRounded;
|
|
|
|
valueDate = valueDate.Date;
|
|
var eodQuery = DbContext.eod_trade.AsQueryable();
|
|
if (clientIdsOfInside != null)
|
|
{
|
|
eodQuery = eodQuery.Where(a => !clientIdsOfInside.Contains(a.ClientId));
|
|
}
|
|
var query = from et in eodQuery
|
|
join t in DbContext.trade on et.TradeId equals t.id
|
|
join etp in DbContext.eod_trade_position on new { et.TradeId, et.ValueDate } equals new { etp.TradeId, etp.ValueDate } into etp_s
|
|
from etp in etp_s.DefaultIfEmpty()
|
|
join etr in DbContext.eod_trade_risk on new { et.TradeId, et.ValueDate } equals new { etr.TradeId, etr.ValueDate } into etr_s
|
|
from etr in etr_s.DefaultIfEmpty()
|
|
where et.ValueDate == valueDate && t.ClientId > 0
|
|
select new InnerPosition
|
|
{
|
|
TradeId = et.TradeId,
|
|
TradeJson = et.TradeJson,
|
|
CallPut = t.OptionType,
|
|
TradeAmount = etp == null ? 0 : etp.Amount,
|
|
PositionPv = etp == null ? 0 : IsPVRounded ? etp.RoundedPv : etp.Pv,
|
|
PositionPnl = etp == null ? 0 : IsPVRounded ? etp.RoundedPositionPnL : etp.PositionPnL,
|
|
ParentTradeId = t.ParentTradeId,
|
|
IsGroup = t.IsGroup,
|
|
DailyPnl = etp == null ? 0 : etp.DailyPnL,
|
|
|
|
Risk = etr == null ? null : new InnerPositionRisk
|
|
{
|
|
Delta = etr.Delta,
|
|
Gamma = etr.Gamma,
|
|
Theta = etr.Theta,
|
|
Rho = etr.Rho,
|
|
Vega = etr.Vega,
|
|
DeltaCash = etr.DeltaCash,
|
|
GammaCash = etr.GammaCash,
|
|
VegaCash = etr.VegaCash,
|
|
Vol = etr.Vol
|
|
}
|
|
};
|
|
|
|
//因为query还在读取中,所以不要用同一个dbcontext
|
|
var extendService = new TradeExtendService(OptUser);
|
|
var eodPriceProvider = new EodPriceProvider(valueDate).Initialize();
|
|
var posList = query.ToArray();
|
|
var groupSumDic = new Dictionary<int, InnerPosition>();
|
|
|
|
foreach (var pos in posList)
|
|
{
|
|
if (pos.IsGroup == 2 && pos.ParentTradeId > 0)
|
|
{
|
|
if (!groupSumDic.TryGetValue(pos.ParentTradeId, out var p))
|
|
{
|
|
groupSumDic[pos.ParentTradeId] = p = new InnerPosition();
|
|
}
|
|
p.PositionPv += pos.PositionPv;
|
|
p.PositionPnl += pos.PositionPnl;
|
|
p.DailyPnl += pos.DailyPnl;
|
|
}
|
|
}
|
|
|
|
foreach (var pos in posList)
|
|
{
|
|
var td = TradeHelper2.Deserialize(pos.TradeJson);
|
|
|
|
if (td == null)
|
|
{
|
|
td = DbContext.trade.FirstOrDefault(n => n.id == pos.TradeId);
|
|
}
|
|
|
|
if (td == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (td.TradeType == "结构化交易")
|
|
{
|
|
if (td.IsGroup == 1)
|
|
{
|
|
td.TradeType = "组合交易";
|
|
|
|
if (groupSumDic.TryGetValue(td.id, out var p))
|
|
{
|
|
pos.PositionPv = p.PositionPv;
|
|
pos.PositionPnl = p.PositionPnl;
|
|
}
|
|
pos.TradeAmount = td.Notional;
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
else if (td.IsGroup == 2)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
extendService.SetTradeExtend(new[] { td }, false);
|
|
|
|
var un = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
|
|
if (un != null)
|
|
{
|
|
pos.TradeAmount /= un.CountRatio;
|
|
pos.CountRatio = un.CountRatio;
|
|
pos.Risk.DeltaInLots = un.ContractSize != 0 ? pos.Risk.Delta / un.ContractSize : pos.Risk.Delta;
|
|
}
|
|
|
|
if (td.TradeType == "收益互换")
|
|
{
|
|
var f = GetEodPayOffSwapPostionFields(td, td.StockEqvNotional, pos);
|
|
result.SwapPositions.Add(f);
|
|
f.SettlePrice = eodPriceProvider.GetPrice(f.GetUnderlyingCode.TrimToNull() ?? f.PayUnderlyingCode
|
|
, settlementType: PS.Config.Company == Configuration.CompanyEnum.厦门象屿 ? SettlementTypeEnum.SettlePrice : SettlementTypeEnum.ClosePrice);
|
|
}
|
|
else if (td.TradeType == "远期")
|
|
{
|
|
var f = GetEodForwardPostionFields(td, pos);
|
|
result.ForwardPositions.Add(f);
|
|
f.SettlePrice = eodPriceProvider.GetPrice(f.UnderlyingCode
|
|
, settlementType: PS.Config.Company == Configuration.CompanyEnum.厦门象屿 ? SettlementTypeEnum.SettlePrice : SettlementTypeEnum.ClosePrice);
|
|
}
|
|
else
|
|
{
|
|
var f = GetEodOptionPostionFields(td, pos);
|
|
result.OptionPositions.Add(f);
|
|
f.SettlePrice = eodPriceProvider.GetPrice(f.UnderlyingCode
|
|
, settlementType: PS.Config.Company == Configuration.CompanyEnum.厦门象屿 ? SettlementTypeEnum.SettlePrice : td.SettlementType);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#region----场外期权----
|
|
|
|
private EodOptionPositionField GetEodOptionPostionFields(trade td, InnerPosition pos)
|
|
{
|
|
var isMoneyness = td.IsMoneynessOption == "是";
|
|
var isUsePremiumRate = td.IsUsePremiumRate == true;
|
|
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
|
|
var volFormat = PS.Config.ErpElement.VolMoreAccurate ? "P4" : "P2";
|
|
|
|
var f = new EodOptionPositionField
|
|
{
|
|
TradeType = td.TradeType,
|
|
StructureType = td.TradeMultipleType,
|
|
|
|
TradeNumber = td.TradeNumber,
|
|
AssetBookName = td.AssetBookName,
|
|
TraderName = td.TraderName,
|
|
ClientName = td.ClientName,
|
|
ExerciseMode = td.ExerciseModeCn,
|
|
CallPut = pos.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 ?? 0,
|
|
Strike = td.Strike.OtcFormatUmPrice(isMoneyness),
|
|
IsMoneynessOption = isMoneyness ? "是" : "否",
|
|
Premium = isUsePremiumRate ? td.PremiumRate.OtcFormat(OtcFormatFlag.premiumRateP) : td.TradeSinglePrice.OtcFormat(OtcFormatFlag.tradeSinglePrice),
|
|
IsUsePremiumRate = isUsePremiumRate ? "是" : "否",
|
|
InitialMargin = td.InitialMargin ?? 0,
|
|
TradeAmount = (td.OriginalNotional ?? 0) / pos.CountRatio,
|
|
TradePrice = td.TradePrice ?? 0,
|
|
StockEqvNotional = td.OriginalStockEqvNotional ?? 0,
|
|
StockEqvNotionalReal = td.StockEqvNotionalReal,
|
|
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 ?? 0,
|
|
Comments = td.Comments,
|
|
|
|
PositionPv = pos.PositionPv,
|
|
PositionPnl = pos.PositionPnl,
|
|
PositionTradeAmount = pos.TradeAmount,
|
|
DailyPnl = pos.DailyPnl
|
|
};
|
|
|
|
if (pos.Risk != null)
|
|
{
|
|
var risk = pos.Risk;
|
|
f.Delta = risk.Delta;
|
|
f.DeltaInLots = risk.DeltaInLots;
|
|
f.DeltaCash = risk.DeltaCash;
|
|
f.Gamma = risk.Gamma;
|
|
f.GammaCash = risk.GammaCash;
|
|
f.Vega = risk.Vega;
|
|
f.VegaCash = risk.VegaCash;
|
|
f.Theta = risk.Theta;
|
|
f.Rho = risk.Rho;
|
|
|
|
f.PositionVol = risk.Vol.ToString(volFormat);
|
|
}
|
|
|
|
if (_context.TryGetClientInfo(td.ClientId, out var clientInfo))
|
|
{
|
|
f.ClientName = clientInfo.Name;
|
|
f.ClientNumber = clientInfo.Number;
|
|
}
|
|
|
|
switch (f.TradeType)
|
|
{
|
|
case "亚式期权":
|
|
SetAsianOption(td.trade_asian_option, f);
|
|
break;
|
|
case "障碍期权":
|
|
SetBarrierOption(td.trade_barrier_option, f, isMoneyness: isMoneyness, isUsePremiumRate: isUsePremiumRate);
|
|
break;
|
|
case "双鲨期权":
|
|
SetDbSharkOption(td.trade_double_sharkfin_option, f, isMoneyness: isMoneyness, isUsePremiumRate: isUsePremiumRate);
|
|
break;
|
|
case "二元期权":
|
|
SetBianryOption(td.trade_binary_option, f, isMoneyness: isMoneyness, isUsePremiumRate: isUsePremiumRate);
|
|
break;
|
|
case "区间累积期权":
|
|
SetRangeAccuralOption(td.trade_rangeaccrual, f, isMoneyness);
|
|
break;
|
|
case "气囊结构":
|
|
SetAirbagOption(td.trade_airbag, f, isMoneyness);
|
|
break;
|
|
case "收益增强结构":
|
|
if (td.trade_underlying_enhance != null)
|
|
{
|
|
f.CallPut = string.Empty;
|
|
f.AnnualizedEnhanceRate = td.trade_underlying_enhance.AnnualizedEnhanceRate.OtcFormatPercent(4);
|
|
}
|
|
break;
|
|
case "凤凰期权":
|
|
SetAutoCallOption(td.trade_autocall, f, isMoneyness);
|
|
break;
|
|
case "雪球期权":
|
|
SetSnowballOption(td.trade_snowball, f, isMoneyness);
|
|
break;
|
|
case "累计期权":
|
|
SetAccumulatorOption(td.trade_accumulator_option, f);
|
|
break;
|
|
case "自定义交易":
|
|
{
|
|
f.StructureTypeSpec = td.StructureType;
|
|
f.StructureIntroduction = td.StructureIntroduction;
|
|
f.ExtendInfo = td.ExtendInfo;
|
|
f.ObservationDates = td.trade_custom?.ObservationDates;
|
|
}
|
|
break;
|
|
case "组合交易":
|
|
{
|
|
f.ExtendInfo = td.ExtendInfo;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (td.TradeType == "凤凰期权" || td.TradeType == "雪球期权")
|
|
{
|
|
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 static void SetAccumulatorOption(trade_accumulator_option option, EodOptionPositionField f)
|
|
{
|
|
if (option != null)
|
|
{
|
|
f.AccumulatorKOBarrier = option.KOBarrier.OtcFormatFlex(2, 2);
|
|
f.AccumulatorPayoffType = option.PayoffType;
|
|
if (option.PayoffType == "固定")
|
|
{
|
|
f.AccumulatorPayoffType = "固定(票息)";
|
|
f.AccumulatorCoupon = option.CouponPercent ? option.Coupon.OtcFormatPercent() : option.Coupon.OtcFormatFlex(2);
|
|
f.AccumulatorCouponDayCount = option.CouponDayCount;
|
|
f.AccumulatorIsAnnualizedCoupon = option.IsFixedCoupon ? "否" : "是";
|
|
}
|
|
f.AccumulatorMultiplier = ConsGlobal.CallPut.IsCall(f.CallPut) ? option.PutMultiplier : option.CallMultiplier;
|
|
f.AccumulatorEarlyTerminate = option.EarlyTerminate ? "是" : "否";
|
|
switch (option.SettlementMode)
|
|
{
|
|
case "现金期末":
|
|
f.AccumulatorSettlementMode = "现金结算(期末)";
|
|
break;
|
|
case "实物交割":
|
|
f.AccumulatorSettlementMode = "实物交割";
|
|
break;
|
|
default:
|
|
f.AccumulatorSettlementMode = "现金结算(当日)";
|
|
break;
|
|
}
|
|
f.AccumulatorAccumuType = option.AccumuType;
|
|
f.ObservationDates = option.KOObservationDates;
|
|
f.SettlementDate = option.KOObservationSettleDates;
|
|
}
|
|
}
|
|
|
|
//雪球期权
|
|
private static void SetSnowballOption(trade_snowball option, EodOptionPositionField f, bool isMoneyness)
|
|
{
|
|
if (option != null)
|
|
{
|
|
f.SnowballKOBarrier = option.KOBarrier.OtcFormatUmPrice(isMoneyness);
|
|
|
|
switch (option.KOPayoffType)
|
|
{
|
|
case KOPayoffTypeEnum.Rebate:
|
|
f.SnowballKOPayoffType = "票息补偿";
|
|
f.SnowballIsAnnualizedCoupon = option.IsFixedCoupon ? "否" : "是";
|
|
f.SnowballKORebate = option.KORebate.OtcFormatPercent();
|
|
f.SnowballAnnualizedPremiumRate = option.AnnualizedPremiumRate.OtcFormatPercent();
|
|
f.SnowballKOObservationSettleDates = option.KOObservationSettleDates;
|
|
break;
|
|
case KOPayoffTypeEnum.ToOption:
|
|
f.SnowballKOPayoffType = KOPayoffTypeEnumHelper.GetDesc(option.KOPayoffType, f.CallPut);
|
|
f.SnowballKOStrike1 = option.SpreadStrikeAtKO1.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
case KOPayoffTypeEnum.ToSpreadOption:
|
|
f.SnowballKOPayoffType = KOPayoffTypeEnumHelper.GetDesc(option.KOPayoffType, f.CallPut);
|
|
f.SnowballKOStrike2 = option.SpreadStrikeAtKO.OtcFormatUmPrice(isMoneyness);
|
|
f.SnowballKOStrike1 = option.SpreadStrikeAtKO1.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
default:
|
|
f.SnowballKOPayoffType = option.KOPayoffType.ToString();
|
|
break;
|
|
}
|
|
|
|
f.SnowballKORebateType = RebateTypeEnumHelper.GetDesc(option.KORebateType);
|
|
f.SnowballKIBarrier = option.KIBarrier.OtcFormatUmPrice(isMoneyness);
|
|
|
|
switch (option.KIPayoffType)
|
|
{
|
|
case KIPayoffTypeEnum.None:
|
|
f.SnowballKIPayoffType = "无";
|
|
break;
|
|
case KIPayoffTypeEnum.ToPutOption:
|
|
f.SnowballKIPayoffType = "敲入转看跌";
|
|
f.SnowballKIStrike1 = option.SpreadStrikeAtMaturity1.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
case KIPayoffTypeEnum.ToPutSpreadOption:
|
|
f.SnowballKIPayoffType = "敲入转熊市价差";
|
|
f.SnowballKIStrike2 = option.SpreadStrikeAtMaturity.OtcFormatUmPrice(isMoneyness);
|
|
f.SnowballKIStrike1 = option.SpreadStrikeAtMaturity1.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
case KIPayoffTypeEnum.ToCallOption:
|
|
f.SnowballKIPayoffType = "敲入转看涨";
|
|
f.SnowballKIStrike1 = option.SpreadStrikeAtMaturity1.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
case KIPayoffTypeEnum.ToCallSpreadOption:
|
|
f.SnowballKIPayoffType = "敲入转牛市价差";
|
|
f.SnowballKIStrike2 = option.SpreadStrikeAtMaturity.OtcFormatUmPrice(isMoneyness);
|
|
f.SnowballKIStrike1 = option.SpreadStrikeAtMaturity1.OtcFormatUmPrice(isMoneyness);
|
|
break;
|
|
default:
|
|
f.SnowballKIPayoffType = option.KIPayoffType.ToString();
|
|
break;
|
|
}
|
|
|
|
f.SnowballNoKICoupon = option.Coupon.OtcFormatPercent();
|
|
var KOObservationDates = option.KOObservationDates ?? string.Empty;
|
|
var index = KOObservationDates.IndexOf(';');
|
|
f.KOObservationDates = index > 0 ? option.KOObservationDates.Substring(0, index) : KOObservationDates;
|
|
f.KIObservationDates = option.ObservationDates;
|
|
f.IsAnnualized = option.IsAnnualized2 ? "是" : "否";
|
|
|
|
f.SnowballKnockInOutStatus = option.KnockInOutStatusCn;
|
|
f.SnowballKnockInOutDate = option.KnockInOutDate.OtcFormatDate();
|
|
}
|
|
}
|
|
|
|
//凤凰期权
|
|
private static void SetAutoCallOption(trade_autocall option, EodOptionPositionField f, bool isMoneyness)
|
|
{
|
|
if (option != null)
|
|
{
|
|
f.AutocallIsAnnualizedCoupon = option.IsFixedCoupon ? "否" : "是";
|
|
f.AutocallCoupon = option.Coupon.OtcFormatPercent();
|
|
f.AutocallCouponBarrier = option.CouponBarrier.OtcFormatUmPrice(isMoneyness);
|
|
f.AutocallCouponPayType = option.CouponPayTypeDesc();
|
|
f.AutocallKOBarrier = option.KOBarrier.OtcFormatUmPrice(isMoneyness);
|
|
f.AutocallKIBarrier = option.KIBarrier.OtcFormatUmPrice(isMoneyness);
|
|
f.AutocallIncludeCouponAfterKI = option.IncludeCouponAfterKI ? "是" : "否";
|
|
f.AutocallKIPayoffType = option.KIPayoffTypeDesc();
|
|
f.AutocallKIStrike1 = option.SpreadStrike1.OtcFormatUmPrice(isMoneyness);
|
|
if (option.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption)
|
|
{
|
|
f.AutocallKIStrike2 = option.SpreadStrike.OtcFormatUmPrice(isMoneyness);
|
|
}
|
|
var KOObservationDates = option.KOObservationDates ?? string.Empty;
|
|
var index = KOObservationDates.IndexOf(';');
|
|
f.KOObservationDates = index > 0 ? option.KOObservationDates.Substring(0, index) : KOObservationDates;
|
|
f.KIObservationDates = option.ObservationDates;
|
|
f.IsAnnualized = option.IsAnnualized2 ? "是" : "否";
|
|
|
|
f.AutocallKnockInOutStatus = option.KnockInOutStatusCn;
|
|
f.AutocallKnockInOutDate = option.KnockInOutDate.OtcFormatDate();
|
|
}
|
|
}
|
|
|
|
//气囊结构
|
|
private static void SetAirbagOption(trade_airbag option, EodOptionPositionField f, bool isMoneyness)
|
|
{
|
|
if (option != null)
|
|
{
|
|
f.AirbagBarrier = option.Barrier.OtcFormatUmPrice(isMoneyness);
|
|
f.AirbagIsDiscrete = option.IsDiscreteMonitored ? "是" : "否";
|
|
f.AirbagKIParticipationRate = option.KIParticipationRate.OtcFormatPercent();
|
|
f.AirbagHasPayoffLimit = option.HasPayoffLimit ? "是" : "否";
|
|
f.AirbagHighStrike = option.HighStrike.OtcFormatUmPrice(isMoneyness);
|
|
f.CallPut = string.Empty;
|
|
}
|
|
}
|
|
|
|
//区间累积
|
|
private static void SetRangeAccuralOption(trade_rangeaccrual option, EodOptionPositionField f, bool isMoneyness)
|
|
{
|
|
if (option != null)
|
|
{
|
|
f.CallPut = string.Empty;
|
|
|
|
f.RangeAccrualLowerRange = option.LowerRange.OtcFormatUmPrice(isMoneyness);
|
|
f.RangeAccrualUpperRange = option.UpperRange.OtcFormatUmPrice(isMoneyness);
|
|
f.RangeAccrualBonusRate = option.BonusRate.OtcFormatPercent(4);
|
|
|
|
f.ObservationDates = option.ObservationDates;
|
|
}
|
|
}
|
|
|
|
//二元期权
|
|
private static void SetBianryOption(trade_binary_option option, EodOptionPositionField f, bool isMoneyness, bool isUsePremiumRate)
|
|
{
|
|
if (option != null)
|
|
{
|
|
f.BinaryPayoffType = option.PayoffType;
|
|
f.BinaryUpperBarrier = option.UpperBarrier.OtcFormatUmPrice(isMoneyness);
|
|
f.BinaryCashOrNothingAmount = OtcFormatHelper.FormatPremium(isUsePremiumRate, option.CashOrNothingAmountRate, option.CashOrNothingAmount);
|
|
f.BinaryCashOrNothingAmountHigh = OtcFormatHelper.FormatPremium(isUsePremiumRate, option.CashOrNothingAmountHighRate, option.CashOrNothingAmountHigh);
|
|
f.BinaryMonitorType = option.MonitorType;
|
|
f.BinaryRebateType = TradeHelper.GetRebateTypeCn(option.RebateType);
|
|
}
|
|
}
|
|
|
|
//双鲨期权
|
|
private static void SetDbSharkOption(trade_double_sharkfin_option option, EodOptionPositionField f, bool isMoneyness, bool isUsePremiumRate)
|
|
{
|
|
if (option != null)
|
|
{
|
|
f.DbSharkBarrierLow = option.BarrierLow.OtcFormatUmPrice(isMoneyness);
|
|
f.DbSharkBarrierHigh = option.BarrierHigh.OtcFormatUmPrice(isMoneyness);
|
|
f.DbSharkStrikeHigh = option.StrikeHigh.OtcFormatUmPrice(isMoneyness);
|
|
f.DbSharkCallParticipationRate = option.CallParticipationRate.OtcFormatPercent();
|
|
f.DbSharkPutParticipationRate = option.PutParticipationRate.OtcFormatPercent();
|
|
f.DbSharkRebate = OtcFormatHelper.FormatPremium(isUsePremiumRate, option.RebateRate, option.Rebate);
|
|
f.DbSharkRebateHigh = OtcFormatHelper.FormatPremium(isUsePremiumRate, option.RebateHighRate, option.RebateHigh);
|
|
f.DbSharkRebateType = TradeHelper.GetRebateTypeCn(option.RebateType);
|
|
f.DbSharkDiscrete = option.Discrete;
|
|
|
|
f.ObservationDates = option.ObservationDates;
|
|
f.DbsharkKnockInOutStatus = option.KnockInOutStatusCn;
|
|
f.DbsharkKnockInOutDate = option.KnockInOutDate.OtcFormatDate();
|
|
}
|
|
}
|
|
|
|
//障碍期权
|
|
private static void SetBarrierOption(trade_barrier_option option, EodOptionPositionField f, bool isMoneyness, bool isUsePremiumRate)
|
|
{
|
|
if (option != null)
|
|
{
|
|
f.BarrierType = option.BarrierType;
|
|
f.BarrierPrice = option.BarrierPrice.OtcFormatUmPrice(isMoneyness);
|
|
f.BarrierPriceHigh = option.UpperBarrierPrice.OtcFormatUmPrice(isMoneyness);
|
|
f.BarrierShift = option.BarrierShift ?? 0;
|
|
f.BarrierRebate = OtcFormatHelper.FormatPremium(isUsePremiumRate, option.RebateRate, option.Rebate);
|
|
f.BarrierRebateType = option.RebateTypeCn;
|
|
f.BarrierDiscrete = option.Discrete;
|
|
|
|
f.ObservationDates = option.ObservationDates;
|
|
f.BarrierKnockInOutDate = option.KnockInOutDate.OtcFormatDate();
|
|
f.BarrierKnockInOutStatus = option.KnockInOutStatusCn;
|
|
}
|
|
}
|
|
|
|
//亚式期权
|
|
private static void SetAsianOption(trade_asian_option option, EodOptionPositionField f)
|
|
{
|
|
if (option != null)
|
|
{
|
|
f.AsianAveragingPeriodStartDate = option.AveragingPeriodStartDate.OtcFormatDate();
|
|
f.AsianPayoffType = option.PayoffTypeCn;
|
|
f.AsianStrikeType = option.StrikeTypeCn;
|
|
f.AsianStrikeGearingFactor = option.StrikeGearingFactor.OtcFormatPercent();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region----收益互换----
|
|
|
|
private EodPayOffSwapPositionField GetEodPayOffSwapPostionFields(trade td, double positionStockEqvNotional, InnerPosition pos)
|
|
{
|
|
var swap = td.trade_swap ?? new trade_swap();
|
|
|
|
var f = new EodPayOffSwapPositionField
|
|
{
|
|
StructureType = ConsGlobal.TradeType.PayoffSwap,
|
|
|
|
TradeNumber = td.TradeNumber,
|
|
AssetBookName = td.AssetBookName,
|
|
TraderName = td.TraderName,
|
|
ClientName = td.ClientName,
|
|
TradeDate = td.TradeDate.OtcFormatDate(),
|
|
ExerciseDate = td.ExerciseDate.OtcFormatDate(),
|
|
Comments = td.Comments,
|
|
|
|
StockEqvNotional = td.OriginalStockEqvNotional ?? 0,
|
|
|
|
GetFixedProfit = swap.GetFixedProfit,
|
|
GetLongShort = swap.GetLongShort,
|
|
GetMarginRate = swap.GetMarginRate.OtcFormatFlex(minDecimals: 0, percent: true),
|
|
GetTradePrice = swap.GetTradePrice,
|
|
GetUnderlyingCode = swap.GetUnderlyingCode,
|
|
GetSpotPrice = swap.GetSpotPrice,
|
|
IsGetFloatingProfit = swap.IsGetFloatingProfit ? "是" : "否",
|
|
|
|
IsPayFloatingProfit = swap.IsPayFloatingProfit ? "是" : "否",
|
|
PayFixedProfit = swap.PayFixedProfit,
|
|
PayLongShort = swap.PayLongShort,
|
|
PayMarginRate = swap.PayMarginRate.OtcFormatPercent(),
|
|
PaySpotPrice = swap.PaySpotPrice,
|
|
PayTradePrice = swap.PayTradePrice,
|
|
PayUnderlyingCode = swap.PayUnderlyingCode,
|
|
|
|
PositionPnl = pos.PositionPnl,
|
|
PositionPv = pos.PositionPv,
|
|
PositionStockEqvNotional = positionStockEqvNotional,
|
|
DailyPnl = pos.DailyPnl
|
|
};
|
|
|
|
if (_context.TryGetClientInfo(td.ClientId, out var clientInfo))
|
|
{
|
|
f.ClientName = clientInfo.Name;
|
|
f.ClientNumber = clientInfo.Number;
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region----远期交易----
|
|
|
|
private EodForwardPositionField GetEodForwardPostionFields(trade td, InnerPosition pos)
|
|
{
|
|
var forward = td.trade_forward ?? new trade_forward();
|
|
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
|
|
|
|
var f = new EodForwardPositionField
|
|
{
|
|
StructureType = td.StructureType.TrimToNull() ?? ConsGlobal.TradeType.Forward,
|
|
|
|
TradeNumber = td.TradeNumber,
|
|
AssetBookName = td.AssetBookName,
|
|
TraderName = td.TraderName,
|
|
ClientName = td.ClientName,
|
|
TradeDate = td.TradeDate.OtcFormatDate(),
|
|
ExerciseDate = td.ExerciseDate.OtcFormatDate(),
|
|
Comments = td.Comments,
|
|
|
|
InitSpotPrice = td.SpotPrice ?? 0,
|
|
AnnualMarginRate = forward.AnnualMarginRate.OtcFormatPercent(),
|
|
AnnualStoragePrice = forward.AnnualStoragePrice,
|
|
BasisGap = td.BasisGap,
|
|
BasisUnderlyingCode = td.BasisUnderlyingCode,
|
|
CallPut = ConsGlobal.CallPut.IsCall(td.CallPut) ? "多头" : "空头",
|
|
NoRiskRate = td.NoRiskRate.OtcFormatPercent(),
|
|
ObservationDates = forward.ObservationDates,
|
|
|
|
Strike = td.Strike ?? 0,
|
|
OpenFee = forward.OpenCommission,
|
|
TotalFee = td.TradePrice ?? 0,
|
|
TradeAmount = (td.OriginalNotional ?? 0) / pos.CountRatio,
|
|
TradeSide = td.BuySell,
|
|
UnderlyingCode = td.UnderlyingCode,
|
|
UnderlyingName = underlying?.UnderlyingName,
|
|
|
|
PositionPv = pos.PositionPv,
|
|
PositionPnl = pos.PositionPnl,
|
|
PositionTradeAmount = pos.TradeAmount,
|
|
DailyPnl = pos.DailyPnl,
|
|
CountRatio = pos.CountRatio
|
|
};
|
|
|
|
if (_context.TryGetClientInfo(td.ClientId, out var clientInfo))
|
|
{
|
|
f.ClientName = clientInfo.Name;
|
|
f.ClientNumber = clientInfo.Number;
|
|
}
|
|
|
|
return f;
|
|
}
|
|
|
|
#endregion
|
|
|
|
/// <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 ? "P4" : "P2";
|
|
|
|
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;
|
|
}
|
|
|
|
public ClientSettleBalancesSumInfo GetClientSettleBalancesSumInfo(IEnumerable<ClientSettleBalance> clientSettleBalances)
|
|
{
|
|
ClientSettleBalancesSumInfo settleBalancesSumInfo = new ClientSettleBalancesSumInfo();
|
|
if (clientSettleBalances.Any())
|
|
{
|
|
settleBalancesSumInfo.WinLossSum = clientSettleBalances.Sum(a => a.WinLoss) * -1;
|
|
settleBalancesSumInfo.TdWinLossSum = clientSettleBalances.Sum(a => a.TdWinLoss) * -1;
|
|
settleBalancesSumInfo.PositionPnlSum = clientSettleBalances.Sum(a => a.PositionPnl) * -1;
|
|
}
|
|
return settleBalancesSumInfo;
|
|
}
|
|
|
|
|
|
class InnerPosition
|
|
{
|
|
public int TradeId { get; set; }
|
|
public int ParentTradeId { get; set; }
|
|
public string TradeJson { get; set; }
|
|
public string CallPut { get; set; }
|
|
public double TradeAmount { get; set; }
|
|
public double PositionPv { get; set; }
|
|
public double PositionPnl { get; set; }
|
|
public InnerPositionRisk Risk { get; set; }
|
|
|
|
public double CountRatio { get; set; } = 1;
|
|
/// <summary>
|
|
/// 当日盈亏
|
|
/// </summary>
|
|
public double DailyPnl { get; set; }
|
|
public int IsGroup { get; set; }
|
|
}
|
|
|
|
class InnerPositionRisk
|
|
{
|
|
public double Delta { get; set; }
|
|
public double DeltaInLots { get; set; }
|
|
public double Gamma { get; set; }
|
|
public double Theta { get; set; }
|
|
public double Rho { get; set; }
|
|
public double Vega { get; set; }
|
|
public double DeltaCash { get; set; }
|
|
public double GammaCash { get; set; }
|
|
public double VegaCash { get; set; }
|
|
public double Vol { get; set; }
|
|
}
|
|
}
|
|
}
|