Files
zszq-trs/YLErpDAL/Modules/IntradayModule/IntradayPositionApiService.cs
2024-05-09 14:06:26 +08:00

723 lines
33 KiB
C#

using YLErp.Commons;
using YLErp.DBModels.Helpers;
using YLErp.Models;
using YLErp.Modules.CalculationModule;
using YLErp.Modules.TradeModule;
using YLErp.QdpModule;
namespace YLErp.Modules.IntradayModule
{
public class IntradayPositionApiService : YLBaseService<IntradaySettleInfoQueryContext>
{
public IntradayPositionApiService(IntradaySettleInfoQueryContext context) : base(context)
{
}
/// <summary>
/// 查询场外期权持仓列表
/// </summary>
public IntradayTradePositionResult GetIntradayPositions(DateTime valueDate, List<int> clientIdsOfInside = null)
{
var result = new IntradayTradePositionResult
{
SwapPositions = new List<IntradayPayOffSwapPositionField>(),
OptionPositions = new List<IntradayOptionPositionField>(),
ForwardPositions = new List<IntradayForwardPositionField>()
};
var IsPVRounded = PS.Config.IsPVRounded;
valueDate = valueDate.Date;
var suspensionUnderlyingIdList = DataCacheProvider.GetUnderlyingDataSource().AsQueryable()
.Where(t => t.UnderlyingStatus == underlying_manager.Status_Suspension).Select(t => t.id).ToList();
var predicate = PredicateBuilder.Create<trade>(t => t.ClientId > 0
&& !clientIdsOfInside.Contains(t.ClientId)
&& ConsTrade.NeedMarginTradeStatusList.Contains(t.TradeStatus)
&& (t.ValidState != "InValid" || t.ValidState == null)
&& (t.TradeType != "结构化交易" || t.IsGroup != 0)
&& (t.ExerciseDate >= valueDate || suspensionUnderlyingIdList.Contains(t.UnderlyingId)));
var tcgQuery = from tc in DbContext.trade_cash
where tc.ValueDate == valueDate && tc.ValidState != ConsGlobal.InValid && !tc.IsDeleted
group tc by tc.TradeId into g
select new
{
TradeId = g.Key,
Amount = g.Sum(t => t.Amount),
Percent = g.Sum(t => t.Action == ClientCashInCashOut.系统操作_平仓费
|| t.Action == ClientCashInCashOut.系统操作_行权费
|| t.Action == ClientCashInCashOut.系统操作_票息 & t.IsLastAction ?
t.UnwindPercentRate : 0)
};
var volType = PS.Config.Is国投 ? "开仓" : "持仓";
var query = from t in DbContext.trade.AsQueryable().Where(predicate)
join risk in DbContext.realtime_trade_risk.Where(tr => tr.ValueDate == valueDate && tr.VolType == volType) on t.id equals risk.TradeId into risks
from risk in risks.DefaultIfEmpty()
join position in DbContext.intraday_trade_position.Where(tp => tp.ValueDate == valueDate) on t.id equals position.TradeId into positions
from position in positions.DefaultIfEmpty()
join tc in tcgQuery on t.id equals tc.TradeId into tc_t
from tc in tc_t.DefaultIfEmpty()
select new InnerPosition
{
Trade = t,
PositionPv = position == null ? 0 : IsPVRounded ? (double)position.RoundedPv : (double)position.Pv,
PositionPnl = position == null ? 0 : IsPVRounded ? position.RoundedPositionPnl : position.PositionPnL,
IsGroup = t.IsGroup,
DailyPnl = position == null ? 0 : (double)position.DailyPnL,
Risk = risk == null ? null : new InnerPositionRisk
{
Delta = risk.Delta ?? 0,
Gamma = risk.Gamma ?? 0,
Theta = risk.Theta ?? 0,
Rho = risk.Rho ?? 0,
Vega = risk.Vega ?? 0,
DeltaCash = risk.DeltaCash ?? 0,
GammaCash = risk.GammaCash ?? 0,
VegaCash = risk.VegaCash ?? 0,
Vol = risk.Vol ?? 0,
SettlePrice = risk.UnderlyingPrice
},
UnwindPercent =tc.Percent,
RealizedPnl = (double?)tc.Amount
};
//DbContext.SetDebugLog();
//因为query还在读取中,所以不要用同一个dbcontext
var extendService = new TradeExtendService(OptUser);
var posList = query.ToArray();
var groupSumDic = new Dictionary<int, InnerPosition>();
var trades = posList.Select(n => n.Trade).ToArray();
BLL.tradeBLL.SetFieldsByTradeType(trades);
foreach (var pos in posList)
{
if (pos.IsGroup == 0)
{
pos.RealizedPnl = TradeCalcHelper.CalcWinLoss(tradeType: pos.Trade.TradeType, buySell: pos.Trade.BuySell,
tradePrice: pos.Trade.TradePrice ?? 0, tcUnwindPercent: pos.UnwindPercent??0, tcAmount: pos.RealizedPnl??0);
}
else if (pos.IsGroup == 2 && pos.Trade.ParentTradeId > 0)
{
if (!groupSumDic.TryGetValue(pos.Trade.ParentTradeId, out var p))
{
groupSumDic[pos.Trade.ParentTradeId] = p = new InnerPosition();
}
p.PositionPv += pos.PositionPv;
p.PositionPnl += pos.PositionPnl;
p.DailyPnl += pos.DailyPnl;
p.RealizedPnl += pos.RealizedPnl = TradeCalcHelper.CalcWinLoss(tradeType: pos.Trade.TradeType, buySell: pos.Trade.BuySell,
tradePrice: pos.Trade.TradePrice ?? 0, tcUnwindPercent: pos.UnwindPercent??0, tcAmount: pos.RealizedPnl??0);
}
}
foreach (var pos in posList)
{
var td = pos.Trade;
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.RealizedPnl = p.RealizedPnl;
pos.DailyPnl = p.DailyPnl;
}
}
else
{
continue;
}
}
else if (td.IsGroup == 2)
{
continue;
}
extendService.SetTradeExtend(new[] { td }, false);
var un = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
if (un != null)
{
pos.CountRatio = un.CountRatio;
pos.ContractSize = un.ContractSize;
}
IntradayPositionField positionField = null;
if (td.TradeType == "收益互换")
{
var f = GetIntradayPayOffSwapPostionFields(td, td.StockEqvNotional, pos);
result.SwapPositions.Add(f);
positionField = f;
}
else if (td.TradeType == "远期")
{
var f = GetIntradayForwardPostionFields(td, pos);
result.ForwardPositions.Add(f);
positionField = f;
}
else
{
var f = GetIntradayOptionPostionFields(td, pos);
result.OptionPositions.Add(f);
positionField = f;
}
if (positionField != null)
{
positionField.ContractSize = pos.ContractSize;
positionField.RealizedPnl = pos.RealizedPnl??0;
positionField.SettlePrice = pos.Risk?.SettlePrice ?? 0;
positionField.DaysToExpiration = QdpCalendarHelper.GetNonHolidayDaysBetween(valueDate, td.ExerciseDate.Value);
}
}
return result;
}
#region----场外期权----
private IntradayOptionPositionField GetIntradayOptionPostionFields(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 IntradayOptionPositionField
{
TradeType = td.TradeType,
StructureType = td.TradeMultipleType,
TradeNumber = td.TradeNumber,
AssetBookName = td.AssetBookName,
TraderName = td.TraderName,
ClientName = td.ClientName,
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 ?? 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 = td.TradeAmount,
DailyPnl = pos.DailyPnl
};
if (pos.Risk != null)
{
var risk = pos.Risk;
f.Delta = risk.Delta;
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, td.CallPut);
break;
case "累计期权":
SetAccumulatorOption(td.trade_accumulator_option, f, isMoneyness, td.CallPut);
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.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 static void SetAccumulatorOption(trade_accumulator_option option, IntradayOptionPositionField f, bool isMoneyness, string callput)
{
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(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, IntradayOptionPositionField f, bool isMoneyness, string callput)
{
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, callput);
f.SnowballKOStrike1 = option.SpreadStrikeAtKO1.OtcFormatUmPrice(isMoneyness);
break;
case KOPayoffTypeEnum.ToSpreadOption:
f.SnowballKOPayoffType = KOPayoffTypeEnumHelper.GetDesc(option.KOPayoffType, 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, IntradayOptionPositionField 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, IntradayOptionPositionField 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, IntradayOptionPositionField 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, IntradayOptionPositionField 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, IntradayOptionPositionField 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, IntradayOptionPositionField 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, IntradayOptionPositionField 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 IntradayPayOffSwapPositionField GetIntradayPayOffSwapPostionFields(trade td, double positionStockEqvNotional, InnerPosition pos)
{
var swap = td.trade_swap ?? new trade_swap();
var f = new IntradayPayOffSwapPositionField
{
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 IntradayForwardPositionField GetIntradayForwardPostionFields(trade td, InnerPosition pos)
{
var forward = td.trade_forward ?? new trade_forward();
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
var f = new IntradayForwardPositionField
{
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 = td.TradeAmount,
DailyPnl = pos.DailyPnl
};
if (_context.TryGetClientInfo(td.ClientId, out var clientInfo))
{
f.ClientName = clientInfo.Name;
f.ClientNumber = clientInfo.Number;
}
return f;
}
#endregion
public ClientSettleBalancesSumInfo GetClientSettleBalancesSumInfo(IEnumerable<ClientSettleBalance> clientSettleBalances)
{
var 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;
}
#region----内部类----
class InnerPosition
{
public trade Trade { get; set; }
public double PositionPv { get; set; }
public double PositionPnl { get; set; }
public InnerPositionRisk Risk { get; set; }
public double CountRatio { get; set; } = 1;
public double ContractSize { get; set; } = 1;
/// <summary>
/// 当日盈亏
/// </summary>
public double DailyPnl { get; set; }
public int IsGroup { get; set; }
public double? UnwindPercent { get; set; }
public double? RealizedPnl { get; set; }
}
class InnerPositionRisk
{
public double Delta { 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; }
public double? SettlePrice { get; set; }
}
#endregion
}
}