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

321 lines
14 KiB
C#

using YLErp.Abstract.DataProviders;
using YLErp.BLL.Calculation;
using YLErp.Enums;
using YLErp.Helpers;
using YLErp.Model.Enum;
using YLErp.Modules.CalculationModule;
using YLErp.QdpModule;
namespace YLErp.BLL.MarginCalculation
{
/// <summary>
/// 伴兴预付金计算
/// </summary>
public class BXMarginCalculation : MarginCalculationBase
{
// 定义一个静态变量来保存类的实例
public static readonly BXMarginCalculation Instance;
static BXMarginCalculation()
{
Instance = new BXMarginCalculation();
}
// 定义私有构造函数,使外界不能创建该类实例
protected BXMarginCalculation()
{
}
public override List<trade_span> RunMarginCalculation(RunMarginCalculationReq req)
{
var resultMap = new List<trade_span>();
var list2 = new List<trade>(req.tradeList.Count);
foreach (var td in req.tradeList)
{
if (td.InitialMargin != null && td.CalcFlag == (int)CalcFlagEnum.IgnoreMarginCalc)
{
var initMargin = td.InitialMargin * (td.Notional / td.OriginalNotional);
var ts = new trade_span()
{
TradeId = td.id,
ClientId = td.ClientId,
ValueDate = req.settleDate,
UnderlyingId = td.UnderlyingId,
UnderlyingCode = td.UnderlyingCode,
OptId = req.userId,
OptName = req.userName,
OptDate = DateTime.Now,
Spv1 = initMargin,
Spv2 = initMargin,
Spv3 = initMargin,
Spv4 = initMargin,
};
ts.SetWorstCastClientPayable();
resultMap.Add(ts);
}
else
{
list2.Add(td);
}
}
resultMap.AddRange(marginCalculation(req.Clone(list2)));
return resultMap;
}
private List<trade_span> marginCalculation(RunMarginCalculationReq req)
{
var resultMap = new Dictionary<int, trade_span>();
var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider);
helper.SetFieldsByTradeType();
using (var db = new YLContext())
{
helper.GetTradVolRateDic(out var tradeVolRateDic, t =>
{
var pclass = helper.GetClient(t.ClientId)?.ProperClientClass;
return pclass != null && pclass.Contains("普通投资者") ? 0.02 : 0;
});
helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices);
var prices = new (string, IPriceProvider)[] {
("up", upLimitPrices),
("down", downLimitPrices)
};
foreach (var price in prices)
{
foreach (var addVolRateDic in new[] { null, tradeVolRateDic })
{
var key = $"{price.Item1}_{(addVolRateDic == null ? 0 : 1)}";
var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(
valueDate: req.settleDate,
calcScenario: req.GetCalcScenario(),
tradeList: req.tradeList,
priceProvider: price.Item2,
pricingRequest: QdpPricingRequest.PV_ONLY,
addVolRateDic: addVolRateDic,
volType: req.volType,
isUseTradeVol: PS.Config.IsTradeVol,
preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin,
isAddVolPercent: false);
if (tradeRiskResult.Results != null && tradeRiskResult.Results.Count > 0)
{
foreach (var item in tradeRiskResult.Results)
{
var client = helper.GetClient(item.Trade);
var clientRatio = client?.Ratio ?? 1.0;
var pv = item.ValueResult.Pv;
//if (item.Trade.TradeType == "收益互换")
//{
// var getclosePrice = req.PriceProvider.GetPrice(item.Trade.trade_swap.GetUnderlyingCode);
// UpdownLimit getprice = helper.GetUpDownLimit(item.Trade.trade_swap.GetUnderlyingCode, getclosePrice);
// var payclosePrice = req.PriceProvider.GetPrice(item.Trade.trade_swap.PayUnderlyingCode);
// UpdownLimit payprice = helper.GetUpDownLimit(item.Trade.trade_swap.PayUnderlyingCode, payclosePrice);
// TradeValueResult optionValue = null;
// if (key == "up_0")
// {
// var priceProvidr = new ManualPriceProvider();
// priceProvidr.SetPrice(item.Trade.trade_swap.GetUnderlyingCode, getprice.UpLimitPrice);
// priceProvidr.SetPrice(item.Trade.trade_swap.PayUnderlyingCode, payprice.UpLimitPrice);
// optionValue = PayoffSwapCalcService.CalcValue(item.Trade, item.Trade.trade_swap, req.settleDate, null, req.CalcMarginType == DBModels.Enums.CalcMarginTypeEnum.EodMargin);
// optionValue = PayoffSwapCalcService.CalcValue(item.Trade, item.Trade.trade_swap, req.settleDate, priceProvidr, req.CalcMarginType == DBModels.Enums.CalcMarginTypeEnum.EodMargin);
// }
// else if (key == "down_0")
// {
// var priceProvidr = new ManualPriceProvider();
// priceProvidr.SetPrice(item.Trade.trade_swap.GetUnderlyingCode, getprice.DownLimitPrice);
// priceProvidr.SetPrice(item.Trade.trade_swap.PayUnderlyingCode, payprice.DownLimitPrice);
// optionValue = PayoffSwapCalcService.CalcValue(item.Trade, item.Trade.trade_swap, req.settleDate, priceProvidr, req.CalcMarginType == DBModels.Enums.CalcMarginTypeEnum.EodMargin);
// }
// pv = optionValue == null ? 0 : optionValue.Pv;
//}
if (!helper.GetSpecialMargin(item.Trade, pv, out var value))
{
if (item.Trade.CalcFlag == (int)CalcFlagEnum.IgnoreMarginCalc)
{
value = item.Trade.InitialMargin ?? 0;
}
else
{
value = GetMargin(item.Trade, item.ValueResult, clientRatio);
}
}
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 "up_1":
tempTradeSpan.Spv2 = value; break;
case "down_0":
tempTradeSpan.Spv3 = value; break;
case "down_1":
tempTradeSpan.Spv4 = value; break;
}
if (contains)
{
tempTradeSpan.SetWorstCastClientPayable();
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.对手方单向追保)
{
value2 = item.Trade.BuySell == "卖出" ? Math.Min(value2, 0) : 0;
}
tempTradeSpan.WorstCastClientPayable = value2;
}
}
}
}
}
return resultMap.Values.ToList();
}
}
private double GetMargin(trade trade, TradeValueResult valueResult, double clientRatio)
{
var value = 0.0;
//预付金不再传入结构化主交易数据
//if (trade.TradeType == "结构化交易")
//{
// if (trade.StructureType != null && trade.StructureType.Contains("跨式"))
// {
// value = valueResult.MaxAbsPv;
// }
// else
// {
// value = valueResult.SellPv;
// }
//}
if (trade.TradeType != "自定义交易")
{
value = valueResult.Pv;
}
return (double.IsNaN(value) ? 0 : value) * clientRatio;
}
public override List<trade_span> CalcClientMargin(CalcClientMarginReq req)
{
var clientSpanNews = new List<ClientSpan>();
using (var db = new YLContext())
{
if (req.tradeSpans != null && req.tradeSpans.Count > 0)
{
var clientGroups = req.tradeSpans.GroupBy(t => t.ClientId);
foreach (var clientGroup in clientGroups)
{
var clientSpan = new ClientSpan
{
ClientId = clientGroup.Key ?? 0,
ValueDate = req.settleDate,
//负数代表客户应缴预付金,正数代表客户应收预付金
Spv1 = -clientGroup.Sum(g => g.Spv1),
Spv2 = -clientGroup.Sum(g => g.Spv2),
Spv3 = -clientGroup.Sum(g => g.Spv3),
Spv4 = -clientGroup.Sum(g => g.Spv4),
WorstCastClientPayable = -clientGroup.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 ?? 0, 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).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;
if (trade.TradeType == "结构化交易" && trade.id > 0)
{
using (var db = new YLContext())
{
trade.SubTrades = db.trade.Where(x => x.ParentTradeId == trade.id).ToList();
}
}
var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq());
if (null != tradeMargin)
{
return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0;
}
return 0.0;
}
}
}