using BaseOUDAL;
using Microsoft.Extensions.Caching.Memory;
using Qdp.Pricing.Base.Utilities;
using YLErp.Abstract;
using YLErp.BLL;
using YLErp.BLL.Eod;
using YLErp.Configuration;
using YLErp.DBModels.Enums;
using YLErp.Models;
using YLErp.Modules.CalculationModule;
using YLErp.Modules.CalculationModule.Abstract;
using YLErp.Modules.TradeRiskCalcModule.Abstract;
using YLErp.Modules.SwapModule;
using YLErp.Modules.TradeRiskCalcModule.TaskRunner;
using YLErp.Modules.VolatilityModule;
using YLErp.QdpModule;
namespace YLErp.Modules.TradeRiskCalcModule
{
///
/// 交易风险计算业务服务
///
public class TradeRiskCalcService
{
static readonly IYcLogger _logger;
static readonly MemoryCache _cache;
static TradeRiskCalcService()
{
_cache = new MemoryCache(new MemoryCacheOptions());
_logger = LogFactory.GetLogger(nameof(TradeRiskCalcService));
}
readonly ITradeRiskCalcContext _context;
readonly IOptionCalcDataProvider _dataProvider;
HashSet _underlyingCodeFilterSet;
readonly string _skipTradeTypes;
public TradeRiskCalcService(ITradeRiskCalcContext context, string skipTradeTypes)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
_dataProvider = CalcCheckHelper.CheckOptionCalcDataProvider(context.OptionCalcDataProvider);
_skipTradeTypes = skipTradeTypes;
}
public TradeRiskCalcService SetUnderlyingFilter(params string[] underlyingCodes)
{
if (underlyingCodes != null && underlyingCodes.Any(n => !string.IsNullOrEmpty(n)))
{
var linq = underlyingCodes.Where(n => !string.IsNullOrEmpty(n));
_underlyingCodeFilterSet = new HashSet(linq, StringComparer.OrdinalIgnoreCase);
}
return this;
}
///
/// 计算
///
public IEnumerable Calculate(ITradeDataSource tradeDataSource, IDataSource manualRiskProvider)
{
if (tradeDataSource == null)
{
throw new ArgumentNullException(nameof(tradeDataSource));
}
IOtcTradeValueCalcContext optionContext = null;
try
{
_logger?.Debug($"[{_context.VolType}]开始计算当前风险>>>>>>>>>");
//构建计算上下文
var sysRiskFreeRate = valuedateBLL.RiskFreeRate * 0.01;
optionContext = _context.CreateOptionValueCalcContext(sysRiskFreeRate);
//场外交易处理
var tradeRiskList = CalcOtcRisks(tradeDataSource, optionContext, manualRiskProvider);
var swapTradeRiskList = CalcSwapRisks(tradeDataSource, optionContext);
tradeRiskList.AddRange(swapTradeRiskList);
var hedgeOptionContext = PS.Config.Is润和 ? new InnerOptionValueCalcContext(DateTime.Today, optionContext) : optionContext;
//对冲交易处理
var hedgingRisk = CalcHedgeTradeRisks(tradeDataSource, hedgeOptionContext);
tradeRiskList.AddRange(hedgingRisk);
//计算每笔期权的盈亏
TradeRiskHelper.CalculateOptionTradePnlWithHedge(tradeRiskList);
_logger?.Debug($"[{_context.VolType}]当前风险计算完毕<<<<<<<<<<<");
return tradeRiskList;
}
finally
{
optionContext?.Dispose();
}
}
#region----场外交易处理----
//场外交易风险和盈亏计算(除收益互换)
private List CalcOtcRisks(ITradeDataSource tradeDataSource
, IOtcTradeValueCalcContext optionContext, IDataSource manualRiskProvider)
{
var volType = _context.VolType;
//准备计算数据
var tradeRiskList = new List();
var otcTrades = tradeDataSource.GetOtcTrades() ?? Enumerable.Empty();
otcTrades = otcTrades.Where(x => x.TradeType != "收益互换");
if (_underlyingCodeFilterSet != null)
{
otcTrades = otcTrades.Where(n => _underlyingCodeFilterSet.Contains(n.UnderlyingCode)).ToArray();
}
_logger?.Debug($"[{volType}]参与计算的场外交易数量:" + otcTrades.Count());
var set = new HashSet(otcTrades.Select(t => t.id));
var tradeCashLookup = _context.GetTrade_Cashes(set).ToLookup(n => n.TradeId);
var ydContexts = GetYdOptionCalculateContexts(_context, optionContext);
DateTime valueDate, preValueDate;
//执行风险计算
foreach (var trad in otcTrades)
{
SetTradeLots(trad);
valueDate = _context.ValueDate;
preValueDate = _context.PreValueDate;
void getTradeCashList(out IEnumerable tradeCashList, out IEnumerable tdTradeCashUnwindList)
{
tradeCashList = tradeCashLookup.FirstOrDefault(a => a.Key == trad.id)?.AsEnumerable() ?? Enumerable.Empty();
tdTradeCashUnwindList = tradeCashList.Where(tc => tc.ValidState != ConsGlobal.InValid && !tc.IsDeleted
&& ClientCashInCashOut.PROFIT_ACTION.Contains(tc.Action) && tc.ValueDate <= valueDate && tc.ValueDate > preValueDate);
}
if (!string.IsNullOrEmpty(_skipTradeTypes) && _skipTradeTypes.Contains(trad.TradeType))
{
var resultRisk = UseManualRisk(trad, volType, manualRiskProvider, (calcRisk, lastPv) =>
{
getTradeCashList(out var tradeCashList, out var tdTradeCashUnwindList);
UpdateOTCPnl(trad, calcRisk, lastPv, tradeCashList: tradeCashList, tdTradeCashUnwindList: tdTradeCashUnwindList);
});
if (resultRisk != null)
{
tradeRiskList.Add(resultRisk);
}
}
else
{
TradingRiskParameter firstRisk = null;
IOtcTradeValueCalcContext ydContext = null;
try
{
var tdOtionContext = optionContext;
ydContext = ydContexts[(int)trad.SettlementType];
if (PS.Config.Is润和)
{
tdOtionContext = new InnerOptionValueCalcContext(DateTime.Today, optionContext);
ydContext = new InnerOptionValueCalcContext(DateTime.Today.AddDays(-1), optionContext);
}
ydContext.UserGroup = tdOtionContext.UserGroup = UserBLL.GetUserGroup(trad.TraderId);
if (volType == "交易曲面分红率0")
{
trad.DividendRate = 0;
}
var result = TradeRiskCalcUtil.CalcTradeRisk(trad, tdOtionContext, out var underlyings);
if (result == null)
{
continue;
}
result.TradeId = trad.id;
if (underlyings == null)
{
continue;
}
var index = 0;
foreach (var underlying in underlyings)
{
var trp = TransformOneUnderlying(underlying, trad, new List { result }, index++);
tradeRiskList.Add(trp);
if (index == 1)
{
firstRisk = trp;
}
}
}
catch (Exception ex)
{
var key = "today_otcTrade_calc_" + trad.id;
if (_cache.Get(key) == null)
{
_cache.Set(key, this, DateTimeOffset.Now.AddMinutes(10));
_logger?.Error(ex, $"[{volType}-{trad.id}-{trad.TradeNumber}]当前风险计算出错");
}
}
if (firstRisk != null)
{
double? lastPv = null;
getTradeCashList(out var tradeCashList, out var tdTradeCashUnwindList);
if (firstRisk.TradeType == "远期")
{
firstRisk.TotalPnl = 0;
}
if (trad.TradeDate < valueDate)
{
var yp = _context.YdEodPositionDataProvider.GetOtcTradePositionData(trad.id, _context.VolType);
if (yp != null)
{
lastPv = yp.Position.Pv;
if (firstRisk.TradeType == "远期")
{
firstRisk.TotalPnl = yp.Position.TotalPnL;
}
}
else
{
lastPv = CalcYdOtcValue(trad, ydContext, tdTradeCashUnwindList, volType, out var spotPrice, out var vol);
if (firstRisk.Debug != null)
{
firstRisk.Debug.Add(spotPrice);
firstRisk.Debug.Add(vol);
}
}
}
UpdateOTCPnl(trad, firstRisk, lastPv, tradeCashList: tradeCashList, tdTradeCashUnwindList: tdTradeCashUnwindList);
}
}
}
AppManager.SetSysInfo(string.Concat("实时风险-", volType, "-计算结果"), tradeRiskList.Count + "条");
_logger?.Debug($"[{volType}]场外交易风险计算完毕");
return tradeRiskList;
}
//场外收益互换交易风险和盈亏计算
private List CalcSwapRisks(ITradeDataSource tradeDataSource, IOtcTradeValueCalcContext optionContext)
{
var volType = _context.VolType;
//厦门象屿
DateTime? nextDateXmxy = null;
if (PS.Config.Company == Configuration.CompanyEnum.厦门象屿)
{
var date = SpecialModule.XiaMenXiangYuHelper.GetRefernceValueDate(_context.ValueDate);
if (date > _context.ValueDate)
{
nextDateXmxy = date;
}
}
//准备计算数据
var tradeRiskList = new List();
var otcTrades = tradeDataSource.GetOtcTrades() ?? Enumerable.Empty();
otcTrades = otcTrades.Where(x => x.TradeType == "收益互换");
var tradeIds = otcTrades.Select(t => t.id).ToList();
var swapTradeService = new SwapTradeService(OptUserInfo.SystemUser);
var swapEodPositionService = new SwapEodPositionService(OptUserInfo.SystemUser);
var tradePositions = swapTradeService.GetSwapPositions(tradeIds, _underlyingCodeFilterSet);
var tradePositionSwapIds = tradePositions.Select(s => s.SwapTradeId).Distinct().ToList();
otcTrades = otcTrades.Where(x => tradePositionSwapIds.Contains(x.id));
_logger?.Debug($"[{volType}]参与计算的场外互换交易数量:" + otcTrades.Count());
var ydContexts = GetYdOptionCalculateContexts(_context, optionContext);
DateTime valueDate = _context.ValueDate;
DateTime preValueDate = _context.PreValueDate;
var swapEodPositions = swapEodPositionService.GetEodPositions(tradePositionSwapIds, valueDate, preValueDate);
var eodSwaps = swapEodPositionService.GetEodSwaps(tradePositionSwapIds, valueDate, preValueDate);
//风险计算
foreach (var trad in otcTrades)
{
var lastSwapEodPositions = swapEodPositions.Where(x => x.SwapTradeId == trad.id).OrderByDescending(o => o.ValueDate).ToList();//可能没有
var lastPositionIds = lastSwapEodPositions.Select(x => x.PositionId).Distinct();
var eodSwap = eodSwaps.Where(x => x.SwapTradeId == trad.id).OrderByDescending(o => o.ValueDate).FirstOrDefault();
var positions = tradePositions.Where(x=>x.SwapTradeId==trad.id).ToList();
if (lastPositionIds.Any())
{
foreach (var item in lastPositionIds)
{
var todayPosition = lastSwapEodPositions.FirstOrDefault(x => x.PositionId == item && x.ValueDate == valueDate);
var lastPosition = lastSwapEodPositions.FirstOrDefault(x => x.PositionId == item && x.ValueDate == preValueDate);
var currentPosition = todayPosition == null ? lastPosition : todayPosition;
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(currentPosition.UnderlyingCode);
var position = tradePositions.FirstOrDefault(f => f.id == item);
var result = new TradeValueResult();
var spotPrice = swapEodPositionService.UnderlyingCodePrice(currentPosition.UnderlyingCode, valueDate,out decimal vobp);
int shortRatio = currentPosition.PositionType == (int)PositionTypeFlag.Long ? 1 : -1;
int directionRatio = currentPosition.PosiDirection == (int)SwapDirectionEnum.收取 ? 1 : -1;
result.Pv =Convert.ToDouble( currentPosition.UnderlyingMarketValue);
result.Delta = directionRatio * shortRatio * Convert.ToDouble(currentPosition.PosiQuantity) * Convert.ToDouble(currentPosition.CountRatio);
result.DeltaCash = result.Delta * Convert.ToDouble(spotPrice);
result.Gamma = 0;
result.GammaCash = 0;
result.Vega = 0;
result.VegaCash = 0;
result.TradingDayTheta = 0;
result.CalendarDayTheta = 0;
result.Rho = 0;
var resultRisk = SwapTransformOneUnderlying(underlying, trad, new List { result }, currentPosition, position);
if (resultRisk != null)
{
tradeRiskList.Add(resultRisk);
}
}
}
}
AppManager.SetSysInfo(string.Concat("实时风险-", volType, "-计算结果"), tradeRiskList.Count + "条");
_logger?.Debug($"[{volType}]互换交易风险计算完毕");
return tradeRiskList;
}
//使用自定义交易风险,注意:应该屏蔽远期
private TradingRiskParameter UseManualRisk(trade trad, string volType, IDataSource manualRiskProvider,
Action UpdateOTCPnl)
{
var usePrePve = false;
var result = new TradeValueResult();
if (!ConsTrade.TradeCompleteStatus.Contains(trad.TradeStatus))
{
var risk = manualRiskProvider?.GetData(trad.id);
if (risk == null)
{
var yp = _context.YdEodPositionDataProvider.GetOtcTradePositionData(trad.id, _context.VolType);
if (yp != null)
{
var rate = trad.Notional / yp.Position.Amount;
result.Pv = yp.Position.Pv * rate;
var ypRisk = yp.Risk;
if (ypRisk != null)
{
result.Delta = ypRisk.Delta * rate;
result.DeltaCash = ypRisk.DeltaCash * rate;
result.Gamma = ypRisk.Gamma * rate;
result.GammaCash = ypRisk.GammaCash * rate;
result.Vega = ypRisk.Vega * rate;
result.VegaCash = ypRisk.VegaCash * rate;
result.TradingDayTheta = ypRisk.Theta * rate;
result.CalendarDayTheta = ypRisk.Theta * rate;
result.Rho = ypRisk.Rho * rate;
}
}
}
else
{
result.Pv = risk.Pv ?? 0;
result.Delta = risk.Delta ?? 0;
result.Gamma = risk.Gamma ?? 0;
result.Vega = risk.Vega ?? 0;
result.TradingDayTheta = risk.Theta ?? 0;
result.CalendarDayTheta = risk.Theta ?? 0;
result.Rho = risk.Rho ?? 0;
if (_dataProvider.UnderlyingPriceProvider.TryGetPrice(trad.UnderlyingCode, out var price))
{
result.DeltaCash = result.Delta * price;
result.GammaCash = result.Gamma * Math.Pow(price, 2) / 100;
result.VegaCash = result.Vega * price;
}
usePrePve = true;
}
}
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trad.UnderlyingCode);
var resultRisk = TransformOneUnderlying(underlying, trad, new List { result }, 0);
if (usePrePve)
{
double? lastPv = null;
var yp = _context.YdEodPositionDataProvider.GetOtcTradePositionData(trad.id, _context.VolType);
if (yp != null)
{
lastPv = yp.Position.Pv;
}
UpdateOTCPnl(resultRisk, lastPv);
}
return resultRisk;
}
//计算场外交易上个交易日市值
private double? CalcYdOtcValue(trade trad, IOtcTradeValueCalcContext ydContext, IEnumerable tdTradeCashUnwindList, string volType
, out double? spotPrice, out double? vol)
{
vol = null;
spotPrice = null;
try
{
if (ConsTrade.TradeCompleteStatus.Contains(trad.TradeStatus))
{
trad.Notional = 0;
}
//计算昨日pv时需要还原昨日的持仓数量
trad.Notional += tdTradeCashUnwindList.Sum(tc => tc.UnwindNotional ?? 0);
var result = TradeRiskCalcUtil.CalcTradeRisk(trad, ydContext, out var underlyings);
if (result != null)
{
vol = result.Vol;
spotPrice = result.SpotPrice;
}
return result?.Pv;
}
catch (Exception ex)
{
var key = "yeday_otcTrade_calc_" + trad.id;
if (_cache.Get(key) == null)
{
_cache.Set(key, this, DateTimeOffset.Now.AddMinutes(10));
_logger?.Error(ex, $"[{volType}-{trad.id}-{trad.TradeNumber}]昨日场外期权交易PV计算出错");
}
return null;
}
}
//获取三种结算方式的昨日交易估值上下文(因为昨日交易有日终价格)
private static YdOptionCalculateContext[] GetYdOptionCalculateContexts(ITradeRiskCalcContext riskContext, IOtcTradeValueCalcContext optionContext)
{
var ydContexts = new YdOptionCalculateContext[3];
ydContexts[(int)SettlementTypeEnum.ClosePrice] =
new YdOptionCalculateContext(riskContext.PreValueDate, optionContext, riskContext.YdEodPriceProvider, riskContext.YdTradeHisDataProvider, SettlementTypeEnum.ClosePrice)
{
CalcScenario = Enums.CalcScenarioEnum.RealtimeRisk
};
ydContexts[(int)SettlementTypeEnum.SettlePrice] =
new YdOptionCalculateContext(riskContext.PreValueDate, optionContext, riskContext.YdEodPriceProvider, riskContext.YdTradeHisDataProvider, SettlementTypeEnum.SettlePrice)
{
CalcScenario = Enums.CalcScenarioEnum.RealtimeRisk
};
ydContexts[(int)SettlementTypeEnum.ReferencePrice] =
new YdOptionCalculateContext(riskContext.PreValueDate, optionContext, riskContext.YdEodPriceProvider, riskContext.YdTradeHisDataProvider, SettlementTypeEnum.ReferencePrice)
{
CalcScenario = Enums.CalcScenarioEnum.RealtimeRisk
};
return ydContexts;
}
///
/// 设置交易记录手数值
///
private void SetTradeLots(trade trad)
{
//成交手数
trad.Lots = TradeLotsCalc.GetLots(trad.UnderlyingCode, trad.OriginalNotional ?? 0);
trad.LotsNewInfo = TradeLotsCalc.GetLots(trad.UnderlyingCode, trad.Notional);
}
#endregion
#region----对冲交易处理----
///
/// 更新对冲交易盈亏数据
///
private IEnumerable CalcHedgeTradeRisks(ITradeDataSource tradeDataSource, IOtcTradeValueCalcContext optionCalcContext)
{
_logger?.Debug($"[{_context.VolType}]对冲交易PNL处理开始");
//获取所有未结算过的对冲交易
var HedgeTradeList = tradeDataSource.GetExchangeTrades() ?? Enumerable.Empty();
if (_underlyingCodeFilterSet != null)
{
HedgeTradeList = HedgeTradeList.Where(n => _underlyingCodeFilterSet.Contains(n.UnderlyingCode)).ToArray();
}
//股票 商品期货临时tradeId
var tempTradeId = -1;
var togetherUnOptionList = new List();
var hedgePnlContext = _context.CreateHedgePnlCalcContext(optionCalcContext);
//昨日持仓信息
var predicat = PredicateBuilder.True();
if (_underlyingCodeFilterSet != null)
{
predicat = predicat.And(t => _underlyingCodeFilterSet.Contains(t.UnderlyingCode));
}
var lastEodPositions = _context.YdEodPositionDataProvider
.GetExchangeTradePositionList(_context.VolType).Where(predicat.Compile()).ToArray();
//计算昨日持仓+新增加交易合计的PV
var hedgePnlList = new HedgePnlCalc(hedgePnlContext).Calculate(HedgeTradeList, lastEodPositions);
//根据是否展示累积盈亏过滤前一交易日已清仓的持仓为0的持仓信息
if (!PS.Config.ShowAccruedTotalPnL)
{
hedgePnlList = hedgePnlList.Where(t => t.HasNewTrade || Math.Abs(t.Notional) != 0).ToList();
}
var calcDeltaT1 = TradeRiskHelper.IsCalcDeltaT1();
foreach (var pnl in hedgePnlList)
{
var um = _dataProvider.UnderlyingDataProvider.GetUnderlying(pnl.UnderlyingCode);
if (um == null)
{
continue;
}
um.Price = pnl.SettlePrice;
var variety = _dataProvider.UnderlyingDataProvider.GetVariety(um.UnderlyingTypeId);
if (variety == null)
{
optionCalcContext.ErrorHandler?.AddError($"{um.UnderlyingCode}没有找到品种信息");
variety = new Variety();
}
var TradeUnitValue = variety?.TradeUnitValue;
var tempRisk = new TradingRiskParameter
{
VarietyCode = variety.VarietyCode?.ToUpperInvariant(),
IsOption = false,
TradeId = tempTradeId--,
UnderlyingId = um.id,
UnderlyingCode = pnl.UnderlyingCode,
UnderlyingName = um?.UnderlyingName ?? string.Empty,
SpotPriceChangePercent = um.GetPriceChangePercent(),
TradeType = pnl.TradeType,
BookId = pnl.BookId,
BuySell = pnl.BuySell,
Notional = pnl.Notional,
Pv = pnl.Pv,
Tv = pnl.TimeValue,
TradePrice = pnl.Cost,
OriginalPrincipalSum = 0,
DailyPnl = pnl.DailyPnL,
TotalPnl = pnl.TotalPnl,
ExercisePnl = pnl.TotalPnl,
SpotPrice = um.Price,
TradeStatus = ConsTrade.确认成交,
InstrumentType = um.UnderlyingInstrumentType,
IsSynthetic = um.IsSynthetic(),
ExchangeOptionCode = pnl.ExchangeOptionCode,
PositionType = pnl.PositionType,
CallPut = pnl.CallPut,
Strike = pnl.Strike,
//风险参数
Delta = pnl.Delta,
SA_Delta = pnl.SA_Delta,
DeltaCash = pnl.DeltaCash,
Gamma = pnl.Gamma,
Vega = pnl.Vega,
GammaCash = pnl.GammaCash,
DeltaInLots = pnl.DeltaInLots,
GammaInLots = pnl.GammaInLots,
Theta = pnl.Theta,
Rho = pnl.Rho,
DdeltaDt = pnl.DdeltaDt,
DdeltaDvol = pnl.DdeltaDvol,
DvegaDt = pnl.DvegaDt,
DvegaDvol = pnl.DvegaDvol,
Lots = pnl.Lots,
LotsNewInfo = pnl.Lots,
Cost = pnl.Cost,
AccruedTotalPnl = pnl.TotalPnl,
ExerciseDate = pnl.ExerciseDate,
Vol = pnl.Vol,
TradeSavedVol = pnl.Vol,
ExOptionPrice = pnl.ExOptionPrice
};
if (calcDeltaT1)
{
tempRisk.DeltaT1 = pnl.TradeType == "场内期权" ? pnl.DeltaT1 : pnl.Delta;
}
if (PS.Config.Is渤海)
{
tempRisk.ExercisePnl = 0.0;
}
tempRisk.OriginalNotionalV = tempRisk.OriginalNotional = tempRisk.Notional;
tempRisk.TradeFlag = (int)EnumTradeTypeUtil.GetTradeFlag(tempRisk.TradeType);
if (Math.Abs(tempRisk.Notional) > 1e-7)
{
tempRisk.Premium = tempRisk.TradePrice / tempRisk.Notional;
tempRisk.StockEqvNotional = Math.Abs(tempRisk.Pv);
tempRisk.BuySell = tempRisk.Notional > 0 ? "买入" : "卖出";
}
else
{
tempRisk.BuySell = string.Empty;
}
if (PS.Config.Company == CompanyEnum.红塔众鑫)
{
var day = QdpCalendarHelper.GetNonHolidayDaysBetween(valuedateBLL.ValueDate
,pnl.ExerciseDate.GetValueOrDefault()); //剩余天数
tempRisk.ThetaNet = Math.Round(pnl.Theta,2) * day;
}
togetherUnOptionList.Add(tempRisk);
}
if (togetherUnOptionList.Any())
{
//更新行权盈亏
foreach (var t in togetherUnOptionList)
{
if (t.TradeType == "场内期权")
{
var pnl = (t.CallPut == "Call" ? 1 : -1) * ((t.SpotPrice ?? 0.0) - (t.Strike ?? 0.0)) * Math.Abs(t.Notional);
pnl = pnl < 0 ? 0 : pnl * EodOperationBase.GetSign(t.BuySell);
t.ExercisePnl = pnl - t.Cost;
}
else
{
t.ExercisePnl = t.Pv - t.Cost;
}
}
}
_logger?.Debug($"[{_context.VolType}]对冲交易PNL计算完毕");
return togetherUnOptionList;
}
#endregion
#region-----tradingRiskParameter-----
//衍生品交易计算结果转换(未考虑多标的期权--待明确业务后重写)
private TradingRiskParameter TransformOneUnderlying(underlying_manager um, trade tradeObj, List optionValueResult, int index)
{
var contractSize = 0d;
var variety = um == null ? null : _dataProvider.UnderlyingDataProvider.GetVariety(um.UnderlyingCode, out contractSize) ?? new Variety();
var sign = EodOperationBase.GetSign(tradeObj.BuySell);
var trp = new TradingRiskParameter
{
IsOption = true,
UnderlyingCode = um?.UnderlyingCode,
UnderlyingId = um?.id,
UnderlyingName = um?.UnderlyingName,
InstrumentType = um?.UnderlyingInstrumentType,
SpotPrice = um?.Price,
SpotPriceChangePercent = um?.GetPriceChangePercent(),
IsGroup = tradeObj.IsGroup,
TradeId = tradeObj.id,
TradeNumber = tradeObj.TradeNumber,
TradeType = tradeObj.TradeType,
StructureType = tradeObj.StructureType,
TradeStatus = tradeObj.TradeStatus,
TradeDate = tradeObj.TradeDate,
TradePrice = (tradeObj.TradePrice ?? 0) * sign,
OriginalPrincipalSum = (tradeObj.OriginalPrincipalSum ?? 0) * sign,
ClientId = tradeObj.ClientId,
ClientName = tradeObj.ClientName,
CallPut = tradeObj.CallPut,
BuySell = tradeObj.BuySell,
BookId = tradeObj.AssetId,
ExerciseMode = tradeObj.ExerciseMode,
ExerciseDate = tradeObj.ExerciseDate,
InitSpotPrice = tradeObj.SpotPrice,
Notional = tradeObj.Notional,
OriginalNotional = tradeObj.OriginalNotional ?? tradeObj.Notional,
StockEqvNotional = tradeObj.StockEqvNotional,
IsMoneynessOption = tradeObj.IsMoneynessOption,
IsPremiumRate = tradeObj.IsUsePremiumRate ?? false,
DividendRate = tradeObj.DividendRate,
NoRiskRate = tradeObj.NoRiskRate,
OpenVol = tradeObj.TradeOpenVolatility ?? 0,
Premium = tradeObj.IsUsePremiumRate == true ? (tradeObj.PremiumRate ?? 0) : (tradeObj.TradeSinglePrice ?? 0),
Lots = tradeObj.Lots,
LotsNewInfo = tradeObj.LotsNewInfo,
TradeSavedVol = tradeObj.TradeSavedVol,
Pv = optionValueResult.Sum(t => t.Pv),
NPv = optionValueResult.Sum(t => t.NPv),
Tv = optionValueResult.Sum(t => t.TimeValue),
Delta = optionValueResult.Sum(t => t.GetDelta(index)),
DeltaT1 = optionValueResult.FirstOrDefault()?.DeltaT1,
SA_Delta = optionValueResult.Sum(t => t.SA_Delta),
Gamma = optionValueResult.Sum(t => t.GetGamma(index)),
Vega = optionValueResult.Sum(t => t.GetVega(index)),
DeltaCash = optionValueResult.Sum(t => t.GetDeltaCash(index)),
GammaCash = optionValueResult.Sum(t => t.GetGammaCash(index)),
TradeFlag = (int)EnumTradeTypeUtil.GetTradeFlag(tradeObj.TradeType, tradeObj.Comments),
AccruedTotalPnl = 0,
CompanyObj = null,
Cost = 0,
DailyPnl = 0,
GammaInLots = 0,
Strike = tradeObj.Strike,
Debug = new List