Files
zszq-trs/YLErpDAL/BLL/MarginCalculation/ZhongLiangMarginCalculation.cs
T
2024-05-09 14:06:26 +08:00

339 lines
17 KiB
C#

using YLErp.Abstract.DataProviders;
using YLErp.BLL.Calculation;
using YLErp.Enums;
using YLErp.Helpers;
using YLErp.Model.Enum;
using YLErp.QdpModule;
namespace YLErp.BLL.MarginCalculation
{
public class ZhongLiangMarginCalculation : MarginCalculationBase
{
public static readonly ZhongLiangMarginCalculation Instance;
static ZhongLiangMarginCalculation()
{
Instance = new ZhongLiangMarginCalculation();
}
public ZhongLiangMarginCalculation()
{
}
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();
helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices);
helper.GetUpDownVolRateDic(out var tradeVolRateDicUp, out var tradeVolRateDicDown);
var prices = new (string, IPriceProvider)[] { ("up", upLimitPrices), ("down", downLimitPrices), ("normal", req.PriceProvider) };
var volRates = new (int, Dictionary<int, double>)[] {
(0, null),
(1, tradeVolRateDicUp),
(2, tradeVolRateDicDown)
};
foreach (var price in prices)
{
foreach (var itemDic in volRates)
{
var key = $"{price.Item1}_{itemDic.Item1}";
if (key == "normal_0")
{
continue;
}
var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(
valueDate: req.settleDate,
tradeList: calcTradeList,
calcScenario: req.GetCalcScenario(),
priceProvider: price.Item2,
pricingRequest: QdpPricingRequest.PV_ONLY,
addVolRateDic: itemDic.Item2,
volType: req.volType,
isUseTradeVol: PS.Config.IsTradeVol,
preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin,
isAddVolPercent: false);
if (tradeRiskResult.Results == null || tradeRiskResult.Results.Count < 1)
{
continue;
}
foreach (var item in tradeRiskResult.Results)
{
var client = helper.GetClient(item.Trade.ClientId);
var clientRatio = client?.Ratio ?? 1.0;
var clientRatio1 = client?.Ratio1 ?? 1.0;
var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan);
var pv = item.ValueResult.Pv;
if (!helper.GetSpecialMargin(item.Trade, pv, out var value))
{
if (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin)
{
value = double.IsNaN(pv) ? 0 : pv * clientRatio1;
}
else
{
value = double.IsNaN(pv) ? 0 : pv * clientRatio;
}
}
if (!contains)
{
resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade);
if (item.Trade.TradeType == "雪球期权" && item.Trade.BuySell == "买入")
{
resultMap[item.Trade.id].IsSingleMargin = true;
resultMap[item.Trade.id].Comment = "雪球买入";
}
}
switch (key)
{
case "up_1":
tempTradeSpan.Spv1 = value; break;
case "up_0":
tempTradeSpan.Spv2 = value; break;
case "up_2":
tempTradeSpan.Spv3 = value; break;
case "normal_1":
tempTradeSpan.Spv4 = value; break;
case "normal_2":
tempTradeSpan.Spv5 = value; break;
case "down_1":
tempTradeSpan.Spv6 = value; break;
case "down_0":
tempTradeSpan.Spv7 = value; break;
case "down_2":
tempTradeSpan.Spv8 = value; break;
}
if (contains)
{
tempTradeSpan.SetWorstCastClientPayable();
if (client != null)
{
var value2 = (double)tempTradeSpan.WorstCastClientPayable;
if (client.MarginOptionType == (int)MarginOptionEnum.单向追保)
{
value2 = item.Trade.BuySell == "卖出" ? 0 : Math.Max(value2, 0);
}
else if (client.MarginOptionType == (int)MarginOptionEnum.对手方单向追保 || client.MarginOptionType == (int)MarginOptionEnum.其他)
{
value2 = 0;
}
else if (client.MarginOptionType == (int)MarginOptionEnum.双向追保)
{
value2 = Math.Max(value2, 0);
}
tempTradeSpan.WorstCastClientPayable = value2;
}
}
}
}
}
return resultMap.Values.ToList();
}
public override List<trade_span> CalcClientMargin(CalcClientMarginReq req)
{
var clientSpanNews = new List<ClientSpan>();
var runMargin = new RunMarginCalculationReq(req.UserInfo);
runMargin.settleDate = req.settleDate;
var helper = new RunMarginCalculationHelper(runMargin, _underlyingDataProvider);
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
where tradeSpan.ValueDate == req.settleDate
select new { trade, tradeSpan }).ToList();
var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId);
foreach (var clientGroup in clientGroups)
{
var varietyGroups = clientGroup.GroupBy(t => t.trade.UnderlyingId).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),
Spv8 = t.Sum(g => g.tradeSpan.Spv8) * (-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(Math.Min(item.Spv1 ?? 0, item.Spv2 ?? 0), item.Spv3 ?? 0), item.Spv4 ?? 0), item.Spv5 ?? 0), item.Spv6 ?? 0), item.Spv7 ?? 0), item.Spv8 ?? 0);
#region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致
var tradeIdList = clientGroup.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();
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 if (item.WorstCastClientPayable == item.Spv7)
{
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv7);
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv7);
}
else
{
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv8);
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv8);
}
#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),
Spv8 = varietyGroups.Sum(g => g.Spv8),
//负数代表客户应缴预付金,正数代表客户应收预付金
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
};
if (!HasTwoSideMargin(clientGroup.Key) && varietyGroups.Sum(g => g.WorstCastClientPayable) > 0)
{
clientSpan.WorstCastClientPayable = 0;
foreach (var item in varietyGroups)
{
var tradeIdList = clientGroup.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();
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = 0);
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = 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;
}
}
public override double GetTradeMargin(GetTradeMarginReq req)
{
var trade = req.trade;
using (var db = new YLContext())
{
if (trade.TradeType == "结构化交易")
{
trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList();
}
}
var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq());
if (null != tradeMargin && tradeMargin.FirstOrDefault() != null)
{
var margin = tradeMargin.FirstOrDefault().WorstCastClientPayable ?? 0.0;
return margin;
}
return 0.0;
}
}
}