866 lines
34 KiB
C#
866 lines
34 KiB
C#
using System.Data;
|
|
using System.Linq.Expressions;
|
|
using YLErp.BLL;
|
|
using YLErp.Configuration;
|
|
using YLErp.DBModels.Enums;
|
|
using YLErp.Models;
|
|
using YLErp.Modules.DataProviderModule;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.Modules.TradeRiskCalcModule
|
|
{
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public class TradingRiskReqService : YLBaseService
|
|
{
|
|
public TradingRiskReqService(OptUserInfo userInfo) : base(userInfo)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取实时风险计算结果
|
|
/// </summary>
|
|
/// <param name="req">筛选条件</param>
|
|
public TradingRiskResult GetResult(TradingRiskReqModel req)
|
|
{
|
|
req ??= new TradingRiskReqModel();
|
|
|
|
if (string.IsNullOrWhiteSpace(req.VolType))
|
|
{
|
|
req.VolType = "对冲";
|
|
}
|
|
if (PS.Config.Company == CompanyEnum.国元固收 && req.DividendRateType == "采集")
|
|
{
|
|
req.VolType = "交易曲面分红率0";
|
|
}
|
|
var calcResult = TradeRiskCalcTaskRunner.GetCalcResult(req.VolType);
|
|
|
|
if (calcResult == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (!req.ForceUpdate && req.CalcStartTime.Year > 2000 && (calcResult.CalcStartTime - req.CalcStartTime).TotalSeconds < 1)
|
|
{
|
|
return new TradingRiskResult
|
|
{
|
|
Message = "#same",
|
|
CalcStartTime = calcResult.CalcStartTime,
|
|
CalcEndTime = calcResult.CalcEndTime
|
|
};
|
|
}
|
|
|
|
//风险对冲累积总盈亏是否统计已过期的场内交易
|
|
TradePnlStaticsDataProvider.Default.IncludeExchangeTrades = PS.Config.ErpElement.RiskAccPnl_SumExpiredExchangeTrades;
|
|
|
|
var result = GroupingResults(calcResult, req);
|
|
|
|
//场内期权使用市场行情价格
|
|
if (!PS.Config.Is光大光子 && req.UseMarketForExOptions)
|
|
{
|
|
SetExOptionMarketValue(result.TradeRiskList);
|
|
}
|
|
|
|
if (req.IsMainList)
|
|
{
|
|
foreach (var item in result.TradeRiskList)
|
|
{
|
|
if (item.viewList == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (req.CalcDeltaRisk)
|
|
{
|
|
item.Notionals = new double[2];
|
|
|
|
foreach (var n in item.viewList)
|
|
{
|
|
if (!ConsTrade.TradeTypesForHedge.Contains(n.TradeType))
|
|
{
|
|
item.Notionals[0] += n.Notional;
|
|
item.Notionals[1] += n.BuySell == "买入" ? n.Notional : -n.Notional;
|
|
}
|
|
}
|
|
}
|
|
|
|
#region 计算gamm定制
|
|
if (PS.Config.Company == CompanyEnum.国贸启润)
|
|
{
|
|
var gammaCustom = 0D;
|
|
foreach (var n in item.viewList)
|
|
{
|
|
|
|
var vol = 0D;
|
|
switch (req.VolType)
|
|
{
|
|
case "对冲":
|
|
vol = n.TradeSavedVol ?? 0;
|
|
break;
|
|
case "持仓":
|
|
default:
|
|
vol = n.Vol;
|
|
break;
|
|
}
|
|
gammaCustom += (-0.5) * n.Gamma * Math.Pow((n.SpotPrice ?? 0), 2) * Math.Pow(vol, 2) / 252;
|
|
}
|
|
item.GammaCustom = gammaCustom;
|
|
}
|
|
#endregion
|
|
|
|
if (string.IsNullOrEmpty(req.RequestFrom) || !req.RequestFrom.StartsWith("a"))
|
|
{
|
|
item.viewList = null;
|
|
}
|
|
|
|
if (PS.Config.Company == Configuration.CompanyEnum.润和)
|
|
{
|
|
item.DeltaCash2 = item.DeltaCash;
|
|
}
|
|
|
|
if (PS.Config.Company == CompanyEnum.红塔众鑫)
|
|
{
|
|
item.ThetaNet = Math.Abs(item.ThetaNet);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//为特定公司处理明细列表数据
|
|
ProcessSubListForCompany(result.TradeRiskList);
|
|
}
|
|
|
|
if (req.ValueTime != null)
|
|
{
|
|
new DongZhengDeltaT1Service().ReCalcDeltaT1(result, req.ValueTime.Value);
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 敲出相关值处理
|
|
/// </summary>
|
|
/// <param name="result"></param>
|
|
private static void KnockOutHandler(TradingRiskResult result)
|
|
{
|
|
if (result != null && result.TradeRiskList != null && result.TradeRiskList.Any())
|
|
{
|
|
foreach (var risk in result.TradeRiskList)
|
|
{
|
|
if (risk.viewList != null && risk.viewList.Count > 0)
|
|
{
|
|
risk.viewList.ForEach(p =>
|
|
{
|
|
CalcContainsKnockOutValue(p);
|
|
});
|
|
risk.PvContainsKnockOut = risk.viewList.Sum(p => p.PvContainsKnockOut);
|
|
risk.GammaInLotsContainsKnockOut = risk.viewList.Sum(p => p.GammaInLotsContainsKnockOut);
|
|
risk.DeltaInLotsContainsKnockOut = risk.viewList.Sum(p => p.DeltaInLotsContainsKnockOut);
|
|
}
|
|
else
|
|
{
|
|
CalcContainsKnockOutValue(risk);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 敲出交易 判断
|
|
/// </summary>
|
|
/// <param name="risk"></param>
|
|
private static void CalcContainsKnockOutValue(TradingRiskParameter risk)
|
|
{
|
|
if (risk.IsKnockOut)
|
|
{
|
|
risk.PvContainsKnockOut = risk.KnockOutPayoff;
|
|
risk.GammaInLotsContainsKnockOut = 0;
|
|
risk.DeltaInLotsContainsKnockOut = 0;
|
|
}
|
|
else
|
|
{
|
|
risk.PvContainsKnockOut = risk.Pv;
|
|
risk.GammaInLotsContainsKnockOut = risk.GammaInLots;
|
|
risk.DeltaInLotsContainsKnockOut = risk.DeltaInLots;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取定价计算实时风险计算结果
|
|
/// </summary>
|
|
public TradingRiskResult GetPriceCalcResult(TradingRiskPriceCalcReqModel req)
|
|
{
|
|
if (req?.Prices == null)
|
|
{
|
|
throw new ArgumentNullException(nameof(req));
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(req.VolType))
|
|
{
|
|
req.VolType = "对冲";
|
|
}
|
|
|
|
var result = TradeRiskCalcTaskRunner.ExecuteFixedPriceCalc(req.VolType, req.Prices.Select(n => n.ToPriceModel()));
|
|
|
|
if (result == null)
|
|
{
|
|
return null;
|
|
}
|
|
var filterReq = new TradingRiskReqModel
|
|
{
|
|
VolType = req.VolType,
|
|
BookIds = req.BookIds,
|
|
ClientIds = req.ClientIds,
|
|
AssetTypes = req.AssetTypes,
|
|
IncludeStock = true,
|
|
UnderlyingCodes = req.Prices.Select(n => n.Code),
|
|
OnlyPosition = req.OnlyPosition
|
|
};
|
|
|
|
result = GroupingResults(result, filterReq);
|
|
|
|
if (req.OnlyPosition)
|
|
{
|
|
foreach (var rl in result.TradeRiskList)
|
|
{
|
|
if (rl.viewList != null)
|
|
{
|
|
rl.viewList = rl.viewList.Where(n => n.HasPosition).ToList();
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 从明细结果数据中汇总到标的级别
|
|
/// </summary>
|
|
public static TradingRiskResult GroupingResults(TradingRiskResult calcResult, TradingRiskReqModel req)
|
|
{
|
|
if (calcResult == null)
|
|
{
|
|
return null;
|
|
}
|
|
KnockOutHandler(calcResult);
|
|
req ??= new TradingRiskReqModel();
|
|
|
|
if (string.IsNullOrWhiteSpace(req.VolType))
|
|
{
|
|
req.VolType = "对冲";
|
|
}
|
|
|
|
var result = calcResult.Clone();
|
|
|
|
result.TradeRiskList = InnerGroupingResults(calcResult, req);
|
|
|
|
foreach (var item in result.TradeRiskList)
|
|
{
|
|
//加\t可以避免品种和标的的代码相同时出现的数据呈现问题
|
|
item.VarietyCode = item.VarietyCode?.Trim() + "\t";
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
#region----静态处理----
|
|
|
|
/// <summary>
|
|
/// 设置场内期权行情价值
|
|
/// </summary>
|
|
private static void SetExOptionMarketValue(IEnumerable<TradingRiskParameter> tradeRiskList)
|
|
{
|
|
foreach (var titem in tradeRiskList)
|
|
{
|
|
if (titem.viewList == null || !titem.viewList.Any(n => n.TradeType == "场内期权"))
|
|
{
|
|
continue;
|
|
}
|
|
var tpvGap = titem.Pv;
|
|
titem.HedgePv = titem.Pv = titem.Tv = 0;
|
|
|
|
foreach (var vitem in titem.viewList)
|
|
{
|
|
if (ConsTrade.TradeTypesForHedge.Contains(vitem.TradeType))
|
|
{
|
|
if (vitem.TradeType == "场内期权")
|
|
{
|
|
var vpvGap = vitem.Pv;
|
|
vitem.Pv = vitem.ExOptionPrice.HasValue ? vitem.Notional * vitem.ExOptionPrice.Value : 0;
|
|
var payoff = (vitem.SpotPrice ?? 0) - (vitem.Strike ?? 0);
|
|
var outOfMoney = vitem.CallPut == "Call" ? payoff < 0 : payoff > 0;
|
|
if (outOfMoney)
|
|
{
|
|
payoff = 0;
|
|
}
|
|
vitem.Tv = vitem.Pv + (payoff * vitem.Notional);
|
|
vpvGap -= vitem.Pv;
|
|
vitem.PnlWithHedge -= vpvGap;
|
|
vitem.AccruedTotalPnl -= vpvGap;
|
|
vitem.DailyPnl -= vpvGap;
|
|
vitem.TotalPnl -= vpvGap;
|
|
vitem.TotalPnlWithHedge -= vpvGap;
|
|
vitem.ExercisePnl -= vpvGap;
|
|
}
|
|
titem.HedgePv += vitem.HedgePv = vitem.Pv;
|
|
}
|
|
|
|
titem.Pv += vitem.Pv;
|
|
titem.Tv += vitem.Tv;
|
|
}
|
|
tpvGap -= titem.Pv;
|
|
titem.PnlWithHedge -= tpvGap;
|
|
titem.AccruedTotalPnl -= tpvGap;
|
|
titem.DailyPnl -= tpvGap;
|
|
titem.TotalPnl -= tpvGap;
|
|
titem.TotalPnlWithHedge -= tpvGap;
|
|
titem.ExercisePnl -= tpvGap;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 为特定公司处理明细列表数据
|
|
/// </summary>
|
|
private static void ProcessSubListForCompany(IEnumerable<TradingRiskParameter> tradeRiskList)
|
|
{
|
|
if (PS.Config.Company == Configuration.CompanyEnum.光大光子 || PS.Config.Company == Configuration.CompanyEnum.广期资本)
|
|
{
|
|
//光子:场外期权的成交份额根据交易方向增加正负号
|
|
foreach (var item in tradeRiskList)
|
|
{
|
|
if (item.viewList == null)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
foreach (var n in item.viewList)
|
|
{
|
|
if (n.BuySell == "卖出" && !ConsTrade.TradeTypesForHedge.Contains(n.TradeType))
|
|
{
|
|
n.OriginalNotionalV = n.OriginalNotional = -Math.Abs(n.OriginalNotional);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (PS.Config.Company == Configuration.CompanyEnum.天示)
|
|
{
|
|
foreach (var item in tradeRiskList)
|
|
{
|
|
if (item.viewList != null)
|
|
{
|
|
foreach (var n in item.viewList)
|
|
{
|
|
if (EnumTradeTypeUtil.IsOption((EnumTradeType)n.TradeFlag) && n.UnderlyingCode != null)
|
|
{
|
|
var adjLots = item.viewList.Where(m => m.TradeType == "商品期货" && n.UnderlyingCode.Equals(m.UnderlyingCode, StringComparison.OrdinalIgnoreCase)).Sum(m => m.Lots) ?? 0;
|
|
adjLots -= n.DeltaInLots;
|
|
n.CompanyObj = new TradingRiskParameter_TianShi
|
|
{
|
|
PositionAdjustLots = adjLots,
|
|
RiskDegree = n.DeltaInLots != 0 ? Math.Abs(adjLots / n.DeltaInLots) : 0
|
|
};
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region----数据合并到组----
|
|
|
|
//Math.Sqrt(243)
|
|
const double Sqrt243 = 15.588457268119896;
|
|
|
|
/// <summary>
|
|
/// 过滤并且聚合结果
|
|
/// </summary>
|
|
private static IEnumerable<TradingRiskParameter> InnerGroupingResults(TradingRiskResult result, TradingRiskReqModel req)
|
|
{
|
|
if (!BuildPredicate(req, out var tradeRiskPredicate, out var pnlStaticsPredicate))
|
|
{
|
|
return Enumerable.Empty<TradingRiskParameter>();
|
|
}
|
|
|
|
var tradeRiskList = result.TradeRiskList;
|
|
|
|
if (tradeRiskPredicate != null)
|
|
{
|
|
tradeRiskList = tradeRiskList.Where(tradeRiskPredicate.Compile()).ToArray();
|
|
}
|
|
|
|
if (!tradeRiskList.Any())
|
|
{
|
|
return Enumerable.Empty<TradingRiskParameter>();
|
|
}
|
|
|
|
if (!req.IsMainList)
|
|
{
|
|
pnlStaticsPredicate = null;
|
|
}
|
|
|
|
var pnlStaticsPredicateFunc = pnlStaticsPredicate?.Compile();
|
|
var accruedTotalPnlStartDate = valuedateBLL.SystemDate.AccruedTotalPnlStartDate ?? DateTime.MinValue;
|
|
|
|
Dictionary<string, double> underlyingStaticsDic = null;
|
|
|
|
if (req.IsMainList)
|
|
{
|
|
//获取历史OTC盈亏统计信息(lastSettleDate换成ValueDate.AddDays(-1))
|
|
var accruedTotalPnlDate = valuedateBLL.GetNonHolidayDefore(result.ValueDate.AddDays(-1));
|
|
var pnlStaticsDatas = TradePnlStaticsDataProvider.Default.GetDatas(accruedTotalPnlDate);
|
|
if (pnlStaticsPredicateFunc != null)
|
|
{
|
|
pnlStaticsDatas = pnlStaticsDatas.Where(pnlStaticsPredicateFunc);
|
|
}
|
|
underlyingStaticsDic = pnlStaticsDatas.Where(x => x.UnderlyingCode != null).GroupBy(n => n.UnderlyingCode.ToUpperInvariant())
|
|
.ToDictionary(g => g.Key, g => g.Sum(n => n.TotalPnl), StringComparer.OrdinalIgnoreCase);
|
|
}
|
|
|
|
Dictionary<string, double> accruedTotalPnLStartingDic = null;
|
|
|
|
if (req.IsMainList && accruedTotalPnlStartDate.Year > 2000)
|
|
{
|
|
IEnumerable<TradePnlStatics> datas;
|
|
if (req.VolType != "对冲")
|
|
{
|
|
datas = AccruedTotalPnlStartingDataSource<eod_trade_position>.Default
|
|
.GetDatas(result.ValueDate, accruedTotalPnlStartDate);
|
|
}
|
|
else
|
|
{
|
|
datas = AccruedTotalPnlStartingDataSource<eod_trade_position_hedgevol>.Default
|
|
.GetDatas(result.ValueDate, accruedTotalPnlStartDate);
|
|
}
|
|
if (pnlStaticsPredicateFunc != null)
|
|
{
|
|
datas = datas.Where(pnlStaticsPredicateFunc);
|
|
}
|
|
accruedTotalPnLStartingDic = datas.Where(x => x.UnderlyingCode != null).GroupBy(e => e.UnderlyingCode).ToDictionary(g => g.Key, g => g.Sum(e => e.TotalPnl));
|
|
}
|
|
|
|
//汇总到标的级别
|
|
var tradeRiskGroupDic = new Dictionary<string, TradingRiskParameter>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
foreach (var trp in tradeRiskList)
|
|
{
|
|
if (string.IsNullOrEmpty(trp.UnderlyingCode))
|
|
{
|
|
if (trp.TradeType == ConsGlobal.TradeType.CashFlow)
|
|
{
|
|
trp.VarietyCode = trp.UnderlyingCode = "现金流";
|
|
}
|
|
else
|
|
{
|
|
trp.VarietyCode = trp.UnderlyingCode = "未知";
|
|
}
|
|
}
|
|
|
|
if (tradeRiskGroupDic.TryGetValue(trp.UnderlyingCode, out var tempTrp))
|
|
{
|
|
tempTrp.AddItem(trp);
|
|
}
|
|
else
|
|
{
|
|
tempTrp = new TradingRiskParameter() { IsOption = false };
|
|
tempTrp.AddItem(trp);
|
|
tradeRiskGroupDic.Add(trp.UnderlyingCode, tempTrp);
|
|
|
|
if (req.IsMainList && underlyingStaticsDic != null)
|
|
{
|
|
tempTrp.AccruedTotalPnl += underlyingStaticsDic.TryGetValue(trp.UnderlyingCode, out var pnl) ? pnl : 0;
|
|
|
|
if (accruedTotalPnLStartingDic != null && accruedTotalPnLStartingDic.TryGetValue(trp.UnderlyingCode, out var startingPnl))
|
|
{
|
|
tempTrp.AccruedTotalPnl -= startingPnl;
|
|
}
|
|
}
|
|
|
|
if (PS.Config.Company == CompanyEnum.广期资本)
|
|
{
|
|
tempTrp.CompanyObj = new TradingRiskParameter_GuangQiZiBen();
|
|
}
|
|
}
|
|
|
|
//广期资本定制
|
|
if (tempTrp.CompanyObj is TradingRiskParameter_GuangQiZiBen gqzbSumObj)
|
|
{
|
|
var basePart = (trp.SpotPrice ?? 0) * trp.Vol / Sqrt243;
|
|
var gqzbObj = new TradingRiskParameter_GuangQiZiBen
|
|
{
|
|
DeltaAdjust = trp.Delta * basePart,
|
|
GammaAdjust = 0.5 * trp.Gamma * basePart
|
|
};
|
|
gqzbSumObj.DeltaAdjust += gqzbObj.DeltaAdjust;
|
|
gqzbSumObj.GammaAdjust += gqzbObj.GammaAdjust;
|
|
trp.CompanyObj = gqzbObj;
|
|
}
|
|
}
|
|
|
|
var values = tradeRiskGroupDic.Values.ToArray();
|
|
|
|
//第二层viewlist
|
|
var subLists = values.SelectMany(n => n.viewList).ToArray();
|
|
|
|
//将第三层的viewlist清除掉
|
|
foreach (var item in subLists)
|
|
{
|
|
item.viewList = null;
|
|
}
|
|
|
|
//只查看持仓数据
|
|
if (req.OnlyPosition)
|
|
{
|
|
if (req.IsMainList)
|
|
{
|
|
values = values.Where(n => n.HasPosition).ToArray();
|
|
}
|
|
else
|
|
{
|
|
foreach (var item in values)
|
|
{
|
|
item.viewList.RemoveAll(n => !n.HasPosition);
|
|
}
|
|
}
|
|
}
|
|
|
|
//对冲delta手数 + deltaT1(手数)
|
|
var calcDeltaT1 = TradeRiskHelper.IsCalcDeltaT1();
|
|
var list = req.IsMainList ? values : values.SelectMany(n => n.viewList);
|
|
foreach (var item in list)
|
|
{
|
|
var un = DataCacheProvider.GetUnderlyingDataSource().GetData(item.UnderlyingCode);
|
|
item.HedgeDeltaLots = un == null || un.ContractSize < 1 ? item.HedgeDelta : item.HedgeDelta / un.ContractSize;
|
|
if (calcDeltaT1)
|
|
{
|
|
item.DeltaT1Lots = un == null || un.ContractSize < 1 ? item.DeltaT1 : item.DeltaT1 / un.ContractSize;
|
|
}
|
|
}
|
|
|
|
//排序
|
|
Array.Sort(values, TradingRiskParameterSortComparer.Default);
|
|
|
|
if (req.Stock || !req.IsMainList)
|
|
{
|
|
return values;
|
|
}
|
|
|
|
//20200619:风险对冲页面品种行的累积总盈亏需要统计已过期标的的累积总盈亏
|
|
|
|
var umDataSource = DataCacheProvider.GetUnderlyingDataSource();
|
|
|
|
//如果在req.OnlyPosition逻辑处理过程中已经把子项全部清掉则需要排除掉此类品种
|
|
var varietySet = values.Where(n => n.viewList != null && n.viewList.Any())
|
|
.Select(n => n.VarietyCode).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
|
|
var dicMaturated = new Dictionary<string, TradingRiskParameter>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
foreach (var kv in underlyingStaticsDic)
|
|
{
|
|
//跳过持仓交易包含的标的
|
|
if (tradeRiskGroupDic.ContainsKey(kv.Key))
|
|
{
|
|
continue;
|
|
}
|
|
var varietyCode = umDataSource.GetData(kv.Key)?.CommodityCode;
|
|
if (!string.IsNullOrWhiteSpace(varietyCode) && varietySet.Contains(varietyCode))
|
|
{
|
|
varietyCode = varietyCode.ToUpperInvariant();
|
|
if (dicMaturated.TryGetValue(varietyCode, out var parm))
|
|
{
|
|
parm.AccruedTotalPnl += NumberHelper.Normalize(kv.Value);
|
|
}
|
|
else
|
|
{
|
|
dicMaturated[varietyCode] = parm = new TradingRiskParameter
|
|
{
|
|
VarietyCode = varietyCode,
|
|
UnderlyingCode = "$$" + varietyCode,
|
|
AccruedTotalPnl = NumberHelper.Normalize(kv.Value)
|
|
};
|
|
}
|
|
|
|
if (accruedTotalPnLStartingDic != null && accruedTotalPnLStartingDic.TryGetValue(kv.Key, out var startingPnl))
|
|
{
|
|
parm.AccruedTotalPnl -= startingPnl;
|
|
}
|
|
}
|
|
}
|
|
|
|
return values.Concat(dicMaturated.Values).ToArray();
|
|
}
|
|
|
|
//构建查询条件(返回false表明根据查询条件筛选后的结果集必然是空)
|
|
private static bool BuildPredicate(TradingRiskReqModel req,
|
|
out Expression<Func<TradingRiskParameter, bool>> tradeRiskPredicate,
|
|
out Expression<Func<TradePnlStatics, bool>> pnlStaticsPredicate)
|
|
{
|
|
tradeRiskPredicate = null;
|
|
pnlStaticsPredicate = null;
|
|
|
|
//用户没有任何绑定的簿记账户
|
|
if (req.UserBookIds != null && !req.UserBookIds.Any())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//簿记账户
|
|
if (!BuildAssetBookPredicate(req, out tradeRiskPredicate, out pnlStaticsPredicate))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (req.IsMainList)
|
|
{
|
|
//标的筛选条件构建(pnlStaticsPredicate将根据tradeRiskPredicate已筛选出来的数据构建标的筛选条件)
|
|
|
|
if (!BuildUnderlyingPredicateForMainList(req, out var pre))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
tradeRiskPredicate = CombinePredicate(tradeRiskPredicate, pre, false);
|
|
}
|
|
else
|
|
{
|
|
BuildUnderlyingPredicateForSubList(req, out var pre);
|
|
|
|
tradeRiskPredicate = CombinePredicate(tradeRiskPredicate, pre, false);
|
|
}
|
|
|
|
//交易对手方
|
|
if (req.ClientIds != null && req.ClientIds.Any())
|
|
{
|
|
var invert = req.IsInvertSelect("客户名称");
|
|
|
|
tradeRiskPredicate = CombinePredicate(tradeRiskPredicate, t => req.ClientIds.Contains(t.ClientId), invert);
|
|
|
|
if (req.IsMainList)
|
|
{
|
|
pnlStaticsPredicate = CombinePredicate(pnlStaticsPredicate, t => req.ClientIds.Contains(t.ClientId), invert);
|
|
}
|
|
}
|
|
|
|
//结构类型
|
|
if (req.AssetTypes != null && req.AssetTypes.Any())
|
|
{
|
|
var invert = req.IsInvertSelect("结构类型");
|
|
var set = req.AssetTypes.Select(n => (int)EnumTradeTypeUtil.GetTradeFlag(n, null)).ToHashSet();
|
|
|
|
tradeRiskPredicate = CombinePredicate(tradeRiskPredicate
|
|
, n => set.Contains(n.TradeFlag) || (set.Contains((int)EnumTradeType.CustomGroup) && n.IsGroup != 0)
|
|
, invert);
|
|
|
|
if (req.IsMainList)
|
|
{
|
|
pnlStaticsPredicate = CombinePredicate(pnlStaticsPredicate, t => req.AssetTypes.Contains(t.AssetType), invert);
|
|
}
|
|
}
|
|
|
|
//权益类风险对冲index3
|
|
if (req.Stock)
|
|
{
|
|
tradeRiskPredicate = CombinePredicate(tradeRiskPredicate
|
|
, t => t.InstrumentType == ConsGlobal.InstrumentType.Stock
|
|
|| t.UnderlyingCode.StartsWith("IF") || t.UnderlyingCode.StartsWith("IH")
|
|
|| t.UnderlyingCode.StartsWith("IC") || t.UnderlyingCode.StartsWith("IO"), false);
|
|
}
|
|
else if (!req.IncludeStock) //商品类风险对冲index2包含股票
|
|
{
|
|
tradeRiskPredicate = CombinePredicate(tradeRiskPredicate, t => t.InstrumentType != ConsGlobal.InstrumentType.Stock, false);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 为主列表页面构建标的筛选条件
|
|
/// </summary>
|
|
private static bool BuildUnderlyingPredicateForMainList(TradingRiskReqModel req
|
|
, out Expression<Func<TradingRiskParameter, bool>> tradeRiskPredicate)
|
|
{
|
|
//定价试算会传入UnderlyingCodes请求参数,否则传入UnderlyingIds参数
|
|
if (req.UnderlyingCodes != null && req.UnderlyingCodes.Any())
|
|
{
|
|
tradeRiskPredicate = PredicateBuilder.Create<TradingRiskParameter>(t => req.UnderlyingCodes.Contains(t.UnderlyingCode, StringComparer.OrdinalIgnoreCase));
|
|
return true;
|
|
}
|
|
|
|
tradeRiskPredicate = null;
|
|
|
|
//标的品种
|
|
if (req.VarietyIds != null && req.VarietyIds.Any())
|
|
{
|
|
var dataSource = DataCacheModule.DataCacheManager.GetVarietyDataSource();
|
|
var varietyCodes = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
foreach (var id in req.VarietyIds)
|
|
{
|
|
var variety = dataSource.GetData(id);
|
|
|
|
if (variety != null)
|
|
{
|
|
varietyCodes.Add(variety.VarietyCode);
|
|
}
|
|
}
|
|
|
|
if (varietyCodes.Any())
|
|
{
|
|
tradeRiskPredicate = CombinePredicate(tradeRiskPredicate, n => varietyCodes.Contains(n.VarietyCode), req.IsInvertSelect("标的品种"));
|
|
}
|
|
else if (!req.IsInvertSelect("标的品种"))
|
|
{
|
|
return false; //筛选条件要包含的品种不存在
|
|
}
|
|
}
|
|
|
|
//品种分类
|
|
if (req.VarietyGroups != null && req.VarietyGroups.Any())
|
|
{
|
|
var varietyCodes = DataCacheModule.DataCacheManager.GetVarietyDataSource()
|
|
.AsQueryable().Where(n => req.VarietyGroups.Contains(n.AssetType))
|
|
.Select(n => n.VarietyCode).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
|
|
if (varietyCodes.Any())
|
|
{
|
|
tradeRiskPredicate = CombinePredicate(tradeRiskPredicate, n => varietyCodes.Contains(n.VarietyCode), req.IsInvertSelect("品种分类"));
|
|
}
|
|
else if (!req.IsInvertSelect("品种分类"))
|
|
{
|
|
return false; //筛选条件要包含的品种分类不存在
|
|
}
|
|
}
|
|
|
|
//标的代码
|
|
if (req.UnderlyingIds != null && req.UnderlyingIds.Any())
|
|
{
|
|
var underlyingCodes = DataCacheModule.DataCacheManager.GetUnderlyingDataSource()
|
|
.AsQueryable().Where(n => req.UnderlyingIds.Contains(n.id))
|
|
.Select(n => n.UnderlyingCode).ToArray();
|
|
|
|
if (underlyingCodes.Any())
|
|
{
|
|
tradeRiskPredicate = CombinePredicate(tradeRiskPredicate
|
|
, t => underlyingCodes.Contains(t.UnderlyingCode, StringComparer.OrdinalIgnoreCase)
|
|
, req.IsInvertSelect("标的代码"));
|
|
}
|
|
else if (!req.IsInvertSelect("标的代码"))
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//为明细列表子页面构建标的筛选条件
|
|
private static void BuildUnderlyingPredicateForSubList(TradingRiskReqModel req
|
|
, out Expression<Func<TradingRiskParameter, bool>> tradeRiskPredicate)
|
|
{
|
|
//取股票板块下的数据
|
|
if (req.SubListCode.StartsWith("$,"))
|
|
{
|
|
var UnderlyingCodes = req.SubListCode.Substring(2).Split(',');
|
|
tradeRiskPredicate = PredicateBuilder.Create<TradingRiskParameter>(t => UnderlyingCodes.Contains(t.UnderlyingCode, StringComparer.OrdinalIgnoreCase));
|
|
}
|
|
//取某品种下的数据
|
|
else if (req.SubListCode.StartsWith("$$"))
|
|
{
|
|
var varietyCode = req.SubListCode.TrimStart('$');
|
|
|
|
tradeRiskPredicate = PredicateBuilder.Create<TradingRiskParameter>(t => varietyCode.Equals(t.VarietyCode, StringComparison.OrdinalIgnoreCase));
|
|
|
|
//标的代码过滤
|
|
if (req.UnderlyingIds != null && req.UnderlyingIds.Any())
|
|
{
|
|
var underlyingCodes = DataCacheModule.DataCacheManager.GetUnderlyingDataSource()
|
|
.AsQueryable().Where(n => req.UnderlyingIds.Contains(n.id))
|
|
.Select(n => n.UnderlyingCode).ToArray();
|
|
|
|
tradeRiskPredicate = CombinePredicate(tradeRiskPredicate
|
|
, t => underlyingCodes.Contains(t.UnderlyingCode, StringComparer.OrdinalIgnoreCase)
|
|
, req.IsInvertSelect("标的代码"));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
tradeRiskPredicate = PredicateBuilder.Create<TradingRiskParameter>(t => req.SubListCode.Equals(t.UnderlyingCode, StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
}
|
|
|
|
//构建簿记账户筛选条件
|
|
private static bool BuildAssetBookPredicate(TradingRiskReqModel req
|
|
, out Expression<Func<TradingRiskParameter, bool>> tradeRiskPredicate
|
|
, out Expression<Func<TradePnlStatics, bool>> pnlStaticsPredicate)
|
|
{
|
|
tradeRiskPredicate = null;
|
|
pnlStaticsPredicate = null;
|
|
|
|
if (req.UserBookIds != null)
|
|
{
|
|
var bookIds = req.UserBookIds.ToHashSet();
|
|
|
|
if (!bookIds.Any())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
tradeRiskPredicate = PredicateBuilder.Create<TradingRiskParameter>(t => bookIds.Contains(t.BookId));
|
|
|
|
if (req.IsMainList)
|
|
{
|
|
pnlStaticsPredicate = PredicateBuilder.Create<TradePnlStatics>(t => bookIds.Contains(t.BookId));
|
|
}
|
|
}
|
|
|
|
if (req.BookIds != null && req.BookIds.Any())
|
|
{
|
|
var invert = req.IsInvertSelect("簿记账户");
|
|
|
|
tradeRiskPredicate = CombinePredicate(tradeRiskPredicate, t => req.BookIds.Contains(t.BookId), invert);
|
|
|
|
if (req.IsMainList)
|
|
{
|
|
pnlStaticsPredicate = CombinePredicate(pnlStaticsPredicate, t => req.BookIds.Contains(t.BookId), invert);
|
|
}
|
|
}
|
|
|
|
if (req.AssetIdGroupList != null && req.AssetIdGroupList.Any())
|
|
{
|
|
var groupBookIds = DataCacheProvider.GetAssetUnitDataSource().AsQueryable()
|
|
.Where(x => req.AssetIdGroupList.Contains(x.GroupId)).Select(x => x.id).ToArray();
|
|
|
|
if (!groupBookIds.Any())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
var invert = req.IsInvertSelect("簿记账户组");
|
|
|
|
tradeRiskPredicate = CombinePredicate(tradeRiskPredicate, t => groupBookIds.Contains(t.BookId), invert);
|
|
|
|
if (req.IsMainList)
|
|
{
|
|
pnlStaticsPredicate = CombinePredicate(pnlStaticsPredicate, t => groupBookIds.Contains(t.BookId), invert);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
[System.Runtime.CompilerServices.MethodImpl(methodImplOptions: System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
|
|
static Expression<Func<T, bool>> CombinePredicate<T>(Expression<Func<T, bool>> basePre, Expression<Func<T, bool>> andPre, bool invertAndPre) where T : class
|
|
{
|
|
return basePre == null ? (invertAndPre ? andPre.Not() : andPre) : (andPre == null ? basePre : basePre.And(invertAndPre ? andPre.Not() : andPre));
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|