723 lines
33 KiB
C#
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
|
|
}
|
|
}
|