546 lines
27 KiB
C#
546 lines
27 KiB
C#
using System.Collections;
|
|
using YLErp.BLL.Calculation;
|
|
using YLErp.DBModels;
|
|
using YLErp.Enums;
|
|
using YLErp.Helpers;
|
|
using YLErp.Model.Enum;
|
|
using YLErp.Modules.DataProviderModule;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.BLL.MarginCalculation
|
|
{
|
|
/// <summary>
|
|
/// 湘财证券
|
|
/// </summary>
|
|
public class XiangCaiMarginCalculation : MarginCalculationBase
|
|
{
|
|
public static readonly XiangCaiMarginCalculation Instance;
|
|
|
|
static XiangCaiMarginCalculation()
|
|
{
|
|
Instance = new XiangCaiMarginCalculation();
|
|
}
|
|
|
|
private XiangCaiMarginCalculation()
|
|
{
|
|
|
|
}
|
|
|
|
public override List<trade_span> RunMarginCalculation(RunMarginCalculationReq req)
|
|
{
|
|
if (req?.tradeList == null || !req.tradeList.Any())
|
|
{
|
|
return new List<trade_span>();
|
|
}
|
|
|
|
var calcTradeList = req.tradeList.ToList();
|
|
|
|
var resultMap = new Dictionary<int, trade_span>();
|
|
|
|
var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider);
|
|
helper.SetFieldsByTradeType();
|
|
var mpProvider = helper.GetMarginParamProvider();
|
|
|
|
var upLimitPrices = new ManualPriceProvider();
|
|
var upLimitPricesTwoThirds = new ManualPriceProvider();
|
|
var upLimitPricesOneThird = new ManualPriceProvider();
|
|
var downLimitPrices = new ManualPriceProvider();
|
|
var downLimitPricesTwoThirds = new ManualPriceProvider();
|
|
var downLimitPricesOneThird = new ManualPriceProvider();
|
|
var normalLimitPrices = new ManualPriceProvider();
|
|
//根据涨跌幅限制以及当日结算价计算涨停价以及跌停价
|
|
foreach (var t in req.tradeList)
|
|
{
|
|
if (upLimitPrices.Contains(t.UnderlyingCode))
|
|
{
|
|
continue;
|
|
}
|
|
if (!mpProvider.TryGetUpdownLimit(t.UnderlyingCode, out var updownLimit, out var isFixed))
|
|
{
|
|
updownLimit = 0.05;
|
|
}
|
|
var price = 0.0;
|
|
switch (req.CalcMarginType)
|
|
{
|
|
case CalcMarginTypeEnum.InitialMargin:
|
|
price = t.SpotPrice ?? 0;//期初价
|
|
break;
|
|
case CalcMarginTypeEnum.None:
|
|
var lastDate = QdpCalendarHelper.GetNonHolidayDefore(req.settleDate.AddDays(-1));
|
|
price = new EodPriceProvider(lastDate, true).GetPrice(t.UnderlyingCode, SettlementTypeEnum.SettlePrice);//昨日结算价
|
|
break;
|
|
case CalcMarginTypeEnum.EodMargin:
|
|
price = req.PriceProvider.GetPrice(t.UnderlyingCode);//结算价
|
|
break;
|
|
}
|
|
|
|
//var eodpriceProvider = new YLErp.Modules.DataProviderModule.EodPriceProvider(req.settleDate);
|
|
//var spotPrice = eodpriceProvider.GetPrice(t.UnderlyingCode, SettlementTypeEnum.ClosePrice);//收盘价
|
|
if (isFixed)
|
|
{
|
|
upLimitPrices.SetPrice(t.UnderlyingCode, price + updownLimit);
|
|
upLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price + (updownLimit * 2.0 / 3.0));
|
|
upLimitPricesOneThird.SetPrice(t.UnderlyingCode, price + (updownLimit / 3.0));
|
|
|
|
downLimitPrices.SetPrice(t.UnderlyingCode, price - updownLimit);
|
|
downLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price - (updownLimit * 2.0 / 3.0));
|
|
downLimitPricesOneThird.SetPrice(t.UnderlyingCode, price - (updownLimit / 3.0));
|
|
}
|
|
else
|
|
{
|
|
upLimitPrices.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + updownLimit) : (1 - updownLimit)));
|
|
upLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + (updownLimit * 2.0 / 3.0)) : (1 - (updownLimit * 2.0 / 3.0))));
|
|
upLimitPricesOneThird.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + (updownLimit / 3.0)) : (1 - (updownLimit / 3.0))));
|
|
|
|
downLimitPrices.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - updownLimit) : (1 + updownLimit)));
|
|
downLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - (updownLimit * 2.0 / 3.0)) : (1 + (updownLimit * 2.0 / 3.0))));
|
|
downLimitPricesOneThird.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - (updownLimit / 3.0)) : (1 + (updownLimit / 3.0))));
|
|
}
|
|
//Normal
|
|
normalLimitPrices.SetPrice(t.UnderlyingCode, price);
|
|
}
|
|
var prices = new[] {
|
|
("up", upLimitPrices),("upTwoThirds", upLimitPricesTwoThirds),("upOneThird", upLimitPricesOneThird),
|
|
("down", downLimitPrices),("downTwoThirds", downLimitPricesTwoThirds),("downOneThird", downLimitPricesOneThird),
|
|
("normal", normalLimitPrices)
|
|
};
|
|
|
|
foreach (var price in prices)
|
|
{
|
|
|
|
var key = $"{price.Item1}_0";
|
|
|
|
var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(
|
|
valueDate: req.settleDate,
|
|
tradeList: calcTradeList,
|
|
calcScenario: req.GetCalcScenario(),
|
|
priceProvider: price.Item2,
|
|
pricingRequest: QdpPricingRequest.PV_ONLY,
|
|
volType: "开仓",
|
|
isUseTradeVol: PS.Config.IsTradeVol,
|
|
preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin);
|
|
|
|
if (tradeRiskResult.Results == null || !tradeRiskResult.Results.Any())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
foreach (var item in tradeRiskResult.Results)
|
|
{
|
|
var prepayment = item.Trade.StockEqvNotional * (item.Trade.trade_snowball?.PrepaymentRatio ?? 0) * (item.Trade.BuySell == "卖出" ? -1 : 1);
|
|
var pv = double.IsNaN(item.ValueResult.Pv) ? 0 : (item.ValueResult.Pv - prepayment);
|
|
|
|
var client = helper.GetClient(item.Trade);
|
|
|
|
if (item.Trade.TradeType == "收益互换" && key != "normal_0" && client.MarginOptionType == (int)MarginOptionEnum.双向追保)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var ratio = client == null ? 1 : (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? client.Ratio1 : client.Ratio) ?? 1;
|
|
if (!helper.GetSpecialMargin(item.Trade, pv, out var value))
|
|
{
|
|
value = pv * ratio;
|
|
}
|
|
if (req.CalcMarginType != CalcMarginTypeEnum.InitialMargin && item.Trade.TradeType == "收益互换")
|
|
{
|
|
value = pv * ratio;
|
|
}
|
|
if (req.CalcMarginType != CalcMarginTypeEnum.InitialMargin && (item.Trade.TradeType == "雪球期权" && item.Trade.trade_snowball.PrepaymentUsed || item.Trade.TradeType == "收益互换"))
|
|
{
|
|
var initialMargin = item.Trade.TradeType == "雪球期权" ? -prepayment : ((item.Trade.trade_swap.GetMarginRate ?? 0) - (item.Trade.trade_swap.PayMarginRate ?? 0)) * item.Trade.StockEqvNotional;
|
|
value = GetComparisonInitialMargin(value, client, item.Trade.TradeType, initialMargin);
|
|
}
|
|
|
|
var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan);
|
|
|
|
if (!contains)
|
|
{
|
|
resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade);
|
|
}
|
|
|
|
switch (key)
|
|
{
|
|
case "up_0":
|
|
tempTradeSpan.Spv1 = value; break;
|
|
case "upTwoThirds_0":
|
|
tempTradeSpan.Spv2 = value; break;
|
|
case "upOneThird_0":
|
|
tempTradeSpan.Spv3 = value; break;
|
|
case "normal_0":
|
|
if (item.Trade.TradeType == "收益互换" && client.MarginOptionType == (int)MarginOptionEnum.双向追保)
|
|
{
|
|
tempTradeSpan.SetAllSpvAndWorst(value);
|
|
}
|
|
tempTradeSpan.Spv4 = value; break;
|
|
case "down_0":
|
|
tempTradeSpan.Spv5 = value; break;
|
|
case "downTwoThirds_0":
|
|
tempTradeSpan.Spv6 = value; break;
|
|
case "downOneThird_0":
|
|
tempTradeSpan.Spv7 = value; break;
|
|
}
|
|
|
|
if (contains)
|
|
{
|
|
tempTradeSpan.SetWorstCastClientPayable();
|
|
}
|
|
|
|
resultMap[item.Trade.id].UnderlyingPrice = req.PriceProvider.GetPrice(item.Trade.UnderlyingCode);
|
|
}
|
|
}
|
|
|
|
return resultMap.Values.ToList();
|
|
}
|
|
|
|
public override List<trade_span> CalcClientMargin(CalcClientMarginReq req)
|
|
{
|
|
var clientSpanNews = new List<ClientSpan>();
|
|
|
|
using var db = new YLContext();
|
|
var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList();
|
|
var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList();
|
|
var underlyingIdList = tradeList.Select(t => t.UnderlyingId).ToList();
|
|
|
|
var underlyingList = db.underlying_manager.AsNoTracking().Where(t => underlyingIdList.Contains(t.id)).ToList();
|
|
|
|
var tradeSpanInfo = (from tradeSpan in req.tradeSpans
|
|
join trade in tradeList on tradeSpan.TradeId equals trade.id
|
|
join um in underlyingList on trade.UnderlyingId equals um.id
|
|
where tradeSpan.ValueDate == req.settleDate
|
|
select new { trade, tradeSpan, um.UnderlyingTypeId, UnderlyingId = um.id }).ToList();
|
|
var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId);
|
|
foreach (var clientGroup in clientGroups)
|
|
{
|
|
var varietyGroups = clientGroup.GroupBy(t => t.UnderlyingTypeId).Select(t => new ClientSpan
|
|
{
|
|
VarietyId = t.Key,
|
|
ClientId = clientGroup.Key,
|
|
ValueDate = req.settleDate,
|
|
Spv1 = t.Sum(g => g.tradeSpan.Spv1) * (-1),
|
|
Spv2 = t.Sum(g => g.tradeSpan.Spv2) * (-1),
|
|
Spv3 = t.Sum(g => g.tradeSpan.Spv3) * (-1),
|
|
Spv4 = t.Sum(g => g.tradeSpan.Spv4) * (-1),
|
|
Spv5 = t.Sum(g => g.tradeSpan.Spv5) * (-1),
|
|
Spv6 = t.Sum(g => g.tradeSpan.Spv6) * (-1),
|
|
Spv7 = t.Sum(g => g.tradeSpan.Spv7) * (-1),
|
|
OptId = req.userId,
|
|
OptName = req.userName,
|
|
OptDate = DateTime.Now,
|
|
SpanType = req.SpanType
|
|
}).ToList();
|
|
foreach (var item in varietyGroups)
|
|
{
|
|
item.WorstCastClientPayable = Math.Min(Math.Min(Math.Min(Math.Min(Math.Min(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0), item.Spv5 ?? 0), item.Spv6 ?? 0), item.Spv7 ?? 0);
|
|
|
|
#region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致
|
|
var tradeIdList = clientGroup.Where(x => x.UnderlyingTypeId == item.VarietyId).Select(x => x.tradeSpan.TradeId);
|
|
var tradeSpansUpdate = db.trade_span.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.ValueDate == req.settleDate).ToList();
|
|
var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.ValueDate == req.settleDate).ToList();
|
|
|
|
//单向追保,客户收取预付金为0
|
|
if (!HasTwoSideMargin(item.ClientId) && item.WorstCastClientPayable > 0)
|
|
{
|
|
item.WorstCastClientPayable = 0;
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = 0);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = 0);
|
|
}
|
|
else
|
|
{
|
|
if (item.WorstCastClientPayable == item.Spv1)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv2)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv3)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv4)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv5)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv5);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv5);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv6)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv6);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv6);
|
|
}
|
|
else
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv7);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv7);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
var clientSpan = new ClientSpan
|
|
{
|
|
ClientId = clientGroup.Key,
|
|
ValueDate = req.settleDate,
|
|
Spv1 = varietyGroups.Sum(g => g.Spv1),
|
|
Spv2 = varietyGroups.Sum(g => g.Spv2),
|
|
Spv3 = varietyGroups.Sum(g => g.Spv3),
|
|
Spv4 = varietyGroups.Sum(g => g.Spv4),
|
|
Spv5 = varietyGroups.Sum(g => g.Spv5),
|
|
Spv6 = varietyGroups.Sum(g => g.Spv6),
|
|
Spv7 = varietyGroups.Sum(g => g.Spv7),
|
|
//负数代表客户应缴预付金,正数代表客户应收预付金
|
|
WorstCastClientPayable = varietyGroups.Sum(g => g.WorstCastClientPayable),
|
|
OptId = req.userId,
|
|
OptName = req.userName,
|
|
OptDate = DateTime.Now,
|
|
SpanType = req.SpanType,
|
|
AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null && req.clientAdditionalMarginDic.TryGetValue(clientGroup.Key, out var dd) ? dd : 0
|
|
};
|
|
|
|
clientSpanNews.Add(clientSpan);
|
|
}
|
|
//span类型为实时删除所有实时计算的交易的预付金信息
|
|
if (req.SpanType == ClientSpan.SpanType_RealTime)
|
|
{
|
|
if (req.RefreshClientIds != null)
|
|
{
|
|
db.BulkDelete<ClientSpan>($"{nameof(ClientSpan.ClientId)} in @ids", new { ids = req.RefreshClientIds });
|
|
}
|
|
else
|
|
{
|
|
db.BulkDelete<ClientSpan>($"{nameof(ClientSpan.SpanType)}=@SpanType", new { req.SpanType });
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (req.ClientIds != null)
|
|
{
|
|
var sql = $"{nameof(ClientSpan.ClientId)} in @ids and {nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0";
|
|
db.BulkDelete<ClientSpan>(sql, new { ids = req.ClientIds });
|
|
}
|
|
else
|
|
{
|
|
var sql = $"{nameof(ClientSpan.ValueDate)}='{req.settleDate.ToSqlDate()}' and {nameof(ClientSpan.SpanType)}={req.SpanType} and {nameof(ClientSpan.ModifiedFlag)}=0";
|
|
db.BulkDelete<ClientSpan>(sql);
|
|
}
|
|
|
|
var clientSpanOldsWithFlag = db.client_span.Where(t => t.ValueDate == req.settleDate && t.SpanType == req.SpanType && t.ModifiedFlag)
|
|
.Select(n => new { n.ValueDate, n.ClientId }).ToList();
|
|
//筛选出可以修改的clientSpan
|
|
clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList();
|
|
}
|
|
if (clientSpanNews.Count > 0)
|
|
{
|
|
MySqlBulkExtensions.BulkInsert(db, clientSpanNews);
|
|
}
|
|
|
|
db.SaveChanges();
|
|
return req.tradeSpans;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 根据追保方向判断和初始预付金比较逻辑
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private double GetComparisonInitialMargin(double value, InnerClient client, string tradeType, double initialMargin)
|
|
{
|
|
if (client.MarginOptionType == (int)MarginOptionEnum.双向追保 || tradeType == "雪球期权")
|
|
{
|
|
if (initialMargin >= 0)
|
|
{
|
|
value = Math.Max(initialMargin, value);
|
|
}
|
|
else
|
|
{
|
|
value = Math.Min(initialMargin, value);
|
|
}
|
|
}
|
|
else if (client.MarginOptionType == (int)MarginOptionEnum.单向追保)
|
|
{
|
|
if (initialMargin >= 0)
|
|
{
|
|
value = Math.Max(initialMargin, Math.Max(value, 0));
|
|
}
|
|
else
|
|
{
|
|
value = Math.Min(initialMargin, Math.Min(value, 0));
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
public static double TradeMargin(RunMarginCalculationReq req, trade t)
|
|
{
|
|
var _underlyingDataProvider = new UnderlyingDataProvider();
|
|
var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider);
|
|
helper.SetFieldsByTradeType();
|
|
var mpProvider = helper.GetMarginParamProvider();
|
|
|
|
var upLimitPrices = new ManualPriceProvider();
|
|
var upLimitPricesTwoThirds = new ManualPriceProvider();
|
|
var upLimitPricesOneThird = new ManualPriceProvider();
|
|
var downLimitPrices = new ManualPriceProvider();
|
|
var downLimitPricesTwoThirds = new ManualPriceProvider();
|
|
var downLimitPricesOneThird = new ManualPriceProvider();
|
|
var normalLimitPrices = new ManualPriceProvider();
|
|
//根据涨跌幅限制以及当日结算价计算涨停价以及跌停价
|
|
//if (upLimitPrices.Contains(t.UnderlyingCode))
|
|
//{
|
|
// continue;
|
|
//}
|
|
if (!mpProvider.TryGetUpdownLimit(t.UnderlyingCode, out var updownLimit, out var isFixed))
|
|
{
|
|
updownLimit = 0.05;
|
|
}
|
|
var price = 0.0;
|
|
switch (req.CalcMarginType)
|
|
{
|
|
case CalcMarginTypeEnum.InitialMargin:
|
|
price = t.SpotPrice ?? 0;//期初价
|
|
break;
|
|
case CalcMarginTypeEnum.None:
|
|
var lastDate = QdpCalendarHelper.GetNonHolidayDefore(req.settleDate.AddDays(-1));
|
|
price = new EodPriceProvider(lastDate, true).GetPrice(t.UnderlyingCode, SettlementTypeEnum.SettlePrice);//昨日结算价
|
|
break;
|
|
case CalcMarginTypeEnum.EodMargin:
|
|
price = req.PriceProvider.GetPrice(t.UnderlyingCode);//结算价
|
|
break;
|
|
}
|
|
if (isFixed)
|
|
{
|
|
upLimitPrices.SetPrice(t.UnderlyingCode, price + updownLimit);
|
|
upLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price + (updownLimit * 2.0 / 3.0));
|
|
upLimitPricesOneThird.SetPrice(t.UnderlyingCode, price + (updownLimit / 3.0));
|
|
|
|
downLimitPrices.SetPrice(t.UnderlyingCode, price - updownLimit);
|
|
downLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price - (updownLimit * 2.0 / 3.0));
|
|
downLimitPricesOneThird.SetPrice(t.UnderlyingCode, price - (updownLimit / 3.0));
|
|
}
|
|
else
|
|
{
|
|
upLimitPrices.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + updownLimit) : (1 - updownLimit)));
|
|
upLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + (updownLimit * 2.0 / 3.0)) : (1 - (updownLimit * 2.0 / 3.0))));
|
|
upLimitPricesOneThird.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 + (updownLimit / 3.0)) : (1 - (updownLimit / 3.0))));
|
|
|
|
downLimitPrices.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - updownLimit) : (1 + updownLimit)));
|
|
downLimitPricesTwoThirds.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - (updownLimit * 2.0 / 3.0)) : (1 + (updownLimit * 2.0 / 3.0))));
|
|
downLimitPricesOneThird.SetPrice(t.UnderlyingCode, price * (price > 0 ? (1 - (updownLimit / 3.0)) : (1 + (updownLimit / 3.0))));
|
|
}
|
|
//Normal
|
|
normalLimitPrices.SetPrice(t.UnderlyingCode, price);
|
|
var prices = new[] {
|
|
("up", upLimitPrices),("upTwoThirds", upLimitPricesTwoThirds),("upOneThird", upLimitPricesOneThird),
|
|
("down", downLimitPrices),("downTwoThirds", downLimitPricesTwoThirds),("downOneThird", downLimitPricesOneThird),
|
|
("normal", normalLimitPrices)
|
|
};
|
|
var values = new ArrayList();
|
|
foreach (var p in prices)
|
|
{
|
|
var key = $"{p.Item1}_0";
|
|
var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(
|
|
valueDate: req.settleDate,
|
|
tradeList: new[] { t },
|
|
calcScenario: req.GetCalcScenario(),
|
|
priceProvider: p.Item2,
|
|
pricingRequest: QdpPricingRequest.PV_ONLY,
|
|
volType: "开仓",
|
|
isUseTradeVol: PS.Config.IsTradeVol,
|
|
preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin);
|
|
|
|
if (tradeRiskResult.Results == null || !tradeRiskResult.Results.Any())
|
|
{
|
|
continue;
|
|
}
|
|
foreach (var item in tradeRiskResult.Results)
|
|
{
|
|
var pv = double.IsNaN(item.ValueResult.Pv) ? 0 : (item.ValueResult.Pv - item.Trade.StockEqvNotional * (item.Trade.trade_snowball?.PrepaymentRatio ?? 0) * (item.Trade.BuySell == "卖出" ? -1 : 1));
|
|
double value = 0;
|
|
if (item.Trade.TradeType == "收益互换")
|
|
{
|
|
var client = helper.GetClient(item.Trade);
|
|
var ratio = client == null ? 1 : (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? client.Ratio1 : client.Ratio) ?? 1;
|
|
value = pv * ratio;
|
|
}
|
|
else
|
|
{
|
|
if (!helper.GetSpecialMargin(item.Trade, pv, out value))
|
|
{
|
|
var client = helper.GetClient(item.Trade);
|
|
var ratio = client == null ? 1 : (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? client.Ratio1 : client.Ratio) ?? 1;
|
|
value = pv * ratio;
|
|
}
|
|
}
|
|
|
|
values.Add(value);
|
|
}
|
|
}
|
|
return (double)values.ToArray().Max();
|
|
}
|
|
|
|
private List<trade_span> RunTradeSpanMarginCalculation(RunMarginCalculationReq req)
|
|
{
|
|
//结果集
|
|
var resultMap = new List<trade_span>();
|
|
|
|
var subTradeList = req.tradeList.Where(x => x.ParentTradeId != 0 && x.IsGroup == 0).GroupBy(x => x.ParentTradeId);
|
|
if (subTradeList.Count() > 0)
|
|
{
|
|
foreach (var item in subTradeList)
|
|
{
|
|
var spans = RunMarginCalculation(req.Clone(item.ToList()));
|
|
var spv1 = spans.Sum(O => O.Spv1 ?? 0);
|
|
var spv2 = spans.Sum(O => O.Spv2 ?? 0);
|
|
var spv3 = spans.Sum(O => O.Spv3 ?? 0);
|
|
var spv4 = spans.Sum(O => O.Spv4 ?? 0);
|
|
var spv5 = spans.Sum(O => O.Spv5 ?? 0);
|
|
var spv6 = spans.Sum(O => O.Spv6 ?? 0);
|
|
var spv7 = spans.Sum(O => O.Spv7 ?? 0);
|
|
|
|
var spvArr = new[] { spv1, spv2, spv3, spv4, spv5, spv6, spv7 };
|
|
var maxSpv = spvArr.Max();
|
|
var index = Array.IndexOf(spvArr, maxSpv);
|
|
spans.ForEach(x => x.WorstCastClientPayable = new[] { x.Spv1, x.Spv2, x.Spv3, x.Spv4, x.Spv5, x.Spv6, x.Spv7 }[index]);
|
|
resultMap.AddRange(spans);
|
|
}
|
|
}
|
|
var singleTradeList = req.tradeList.Where(O => O.ParentTradeId == 0).ToList();
|
|
if (singleTradeList.Count > 0)
|
|
{
|
|
resultMap.AddRange(RunMarginCalculation(req.Clone(singleTradeList)));
|
|
}
|
|
return resultMap;
|
|
}
|
|
|
|
public override double GetTradeMargin(GetTradeMarginReq req)
|
|
{
|
|
using var db = new YLContext();
|
|
if (req.trade.TradeType == "结构化交易")
|
|
{
|
|
req.trade.SubTrades = db.trade.Where(x => x.ParentTradeId == req.realTradeId).ToList();
|
|
}
|
|
|
|
var marginReq = req.GetRunMarginCalculationReq();
|
|
if (req.trade.IsGroup == 1)
|
|
{
|
|
marginReq.tradeList = db.trade.Where(x => x.ParentTradeId == req.realTradeId).ToList();
|
|
}
|
|
var tradeMargin = RunMarginCalculation(marginReq);
|
|
if (null != tradeMargin)
|
|
{
|
|
var margin = req.trade.IsGroup == 1 ? tradeMargin.Sum(x => x.WorstCastClientPayable ?? 0) : (tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0);
|
|
return margin;
|
|
}
|
|
return 0.0;
|
|
}
|
|
}
|
|
}
|