542 lines
28 KiB
C#
542 lines
28 KiB
C#
using YLErp.BLL.Calculation;
|
|
using YLErp.Enums;
|
|
using YLErp.Helpers;
|
|
using YLErp.Modules.DataProviderModule;
|
|
using YLErp.Modules.MarginModule;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.BLL.MarginCalculation
|
|
{
|
|
/// <summary>
|
|
/// 瑞达预付金计算
|
|
/// </summary>
|
|
public class RDMarginCalculation : MarginCalculationBase
|
|
{
|
|
// 定义一个静态变量来保存类的实例
|
|
public static readonly RDMarginCalculation Instance;
|
|
|
|
static RDMarginCalculation()
|
|
{
|
|
Instance = new RDMarginCalculation();
|
|
}
|
|
|
|
// 定义私有构造函数,使外界不能创建该类实例
|
|
protected RDMarginCalculation()
|
|
{
|
|
}
|
|
|
|
public override List<trade_span> RunMarginCalculation(RunMarginCalculationReq req)
|
|
{
|
|
if (req?.tradeList == null || !req.tradeList.Any())
|
|
{
|
|
return new List<trade_span>();
|
|
}
|
|
|
|
var resultMap = new Dictionary<int, trade_span>();
|
|
|
|
var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider);
|
|
|
|
helper.SetFieldsByTradeType();
|
|
|
|
var mpProvider = helper.GetMarginParamProvider();
|
|
var tradeVolatilityRateDic = new Dictionary<int, double>();
|
|
var calcTradeList = req.tradeList.ToList();
|
|
var twoMarginClietIds = new HashSet<int>();
|
|
|
|
foreach (var t in req.tradeList)
|
|
{
|
|
var volRate = 0d;
|
|
var price = req.PriceProvider.GetPrice(t.UnderlyingCode);
|
|
if (t.OptionType == "看涨" && price / t.ActualStrike < 0.9 || t.OptionType == "看跌" && price / t.ActualStrike > 1.1)
|
|
{
|
|
volRate = 0.2;
|
|
}
|
|
else
|
|
{
|
|
volRate = mpProvider.GetVolatilityRate(t.UnderlyingCode) ?? 0;
|
|
}
|
|
if (volRate > 0)
|
|
{
|
|
tradeVolatilityRateDic[t.id] = volRate;
|
|
}
|
|
|
|
//if (t.id > 0 && t.TradeType != "掉期"
|
|
// && !twoMarginClietIds.Contains(t.ClientId)
|
|
// && !twoMarginClietIds.Contains(~t.ClientId))
|
|
//{
|
|
// var client = helper.GetClient(t.ClientId);
|
|
// if (client != null && client.MarginOptionType == (int)MarginOptionEnum.双向追保)
|
|
// {
|
|
// twoMarginClietIds.Add(t.ClientId);
|
|
// }
|
|
// else
|
|
// {
|
|
// twoMarginClietIds.Add(~t.ClientId);
|
|
// }
|
|
//}
|
|
}
|
|
|
|
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 = req.PriceProvider.GetPrice(t.UnderlyingCode);
|
|
|
|
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)
|
|
{
|
|
foreach (var addVolRateDic in new[] { null, tradeVolatilityRateDic })
|
|
{
|
|
var key = $"{price.Item1}_{(addVolRateDic == null ? 0 : 1)}";
|
|
|
|
var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(
|
|
valueDate: req.settleDate,
|
|
tradeList: calcTradeList,
|
|
calcScenario: req.GetCalcScenario(),
|
|
priceProvider: price.Item2,
|
|
pricingRequest: QdpPricingRequest.BASIC_PRICING,
|
|
addVolRateDic: addVolRateDic,
|
|
volType: req.volType,
|
|
isUseTradeVol: PS.Config.IsTradeVol,
|
|
preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin,
|
|
isAddVolPercent: false);
|
|
if (tradeRiskResult.Results == null || !tradeRiskResult.Results.Any())
|
|
{
|
|
continue;
|
|
}
|
|
foreach (var item in tradeRiskResult.Results)
|
|
{
|
|
if (item.Trade.StructureType == "掉期")
|
|
{
|
|
continue;
|
|
}
|
|
|
|
var pv = double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv;
|
|
|
|
if (!helper.GetSpecialMargin(item.Trade, pv, out var value))
|
|
{
|
|
var clientRatio = helper.GetClient(item.Trade)?.Ratio ?? 1.0;
|
|
value = pv * 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_1":
|
|
tempTradeSpan.Spv1 = value; break;
|
|
case "upTwoThirds_1":
|
|
tempTradeSpan.Spv2 = value; break;
|
|
case "upOneThird_1":
|
|
tempTradeSpan.Spv3 = value; break;
|
|
case "normal_1":
|
|
tempTradeSpan.Spv4 = value; break;
|
|
case "down_1":
|
|
tempTradeSpan.Spv5 = value; break;
|
|
case "downTwoThirds_1":
|
|
tempTradeSpan.Spv6 = value; break;
|
|
case "downOneThird_1":
|
|
tempTradeSpan.Spv7 = value; break;
|
|
case "normal_0":
|
|
tempTradeSpan.Delta = item.ValueResult.Delta; break;
|
|
}
|
|
|
|
if (contains)
|
|
{
|
|
tempTradeSpan.SetWorstCastClientPayable();
|
|
}
|
|
|
|
resultMap[item.Trade.id].UnderlyingPrice = req.PriceProvider.GetPrice(item.Trade.UnderlyingCode);
|
|
}
|
|
}
|
|
|
|
if (price.Item1 == "normal")
|
|
{
|
|
var lastSettleDate = QdpCalendarHelper.GetNonHolidayDefore(req.settleDate.AddDays(-1));
|
|
|
|
var tradeRiskResultNormal = CalculatorHelper.CalculateRisksForTrades(
|
|
valueDate: lastSettleDate,
|
|
tradeList: calcTradeList,
|
|
calcScenario: req.GetCalcScenario(),
|
|
priceProvider: price.Item2,
|
|
pricingRequest: QdpPricingRequest.BASIC_PRICING,
|
|
addVolRateDic: null,
|
|
volType: req.volType,
|
|
isUseTradeVol: PS.Config.IsTradeVol,
|
|
preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin,
|
|
isAddVolPercent: false);
|
|
if (tradeRiskResultNormal.Results != null && tradeRiskResultNormal.Results.Count > 0)
|
|
{
|
|
foreach (var item in tradeRiskResultNormal.Results)
|
|
{
|
|
if (item.Trade.StructureType != "掉期")
|
|
{
|
|
var pv = double.IsNaN(item.ValueResult.Pv) ? 0 : item.ValueResult.Pv;
|
|
|
|
if (!helper.GetSpecialMargin(item.Trade, pv, out var value))
|
|
{
|
|
var clientRatio = helper.GetClient(item.Trade)?.Ratio ?? 1.0;
|
|
value = pv * clientRatio;
|
|
}
|
|
|
|
resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan);
|
|
tempTradeSpan.Spv = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//foreach (var item in resultMap.Values)
|
|
//{
|
|
// if (item.ClientId > 0 && twoMarginClietIds.Contains(item.ClientId.Value))
|
|
// {
|
|
// var clone = item.Clone();
|
|
// clone.ReverseSpv().SetWorstCastClientPayable();
|
|
// item.WorstCastClientPayable += clone.WorstCastClientPayable ?? 0;
|
|
// item.SetAllSpv(item.WorstCastClientPayable ?? 0);
|
|
// }
|
|
//}
|
|
|
|
var tradeListDQ = req.tradeList.Where(x => x.StructureType == "掉期").ToList();
|
|
|
|
tradeListDQ.ForEach(x =>
|
|
{
|
|
var contains = resultMap.TryGetValue(x.id, out var tempTradeSpan);
|
|
if (!contains)
|
|
{
|
|
resultMap[x.id] = tempTradeSpan = helper.CreateTradeSpan(x);
|
|
}
|
|
|
|
var eodPrice = req.PriceProvider.GetPrice(x.UnderlyingCode);
|
|
if (x.SpotPrice != null && x.SpotPrice != 0 && (Math.Abs(eodPrice / x.SpotPrice.Value) > 1.05 && x.BuySell == "买入" || Math.Abs(eodPrice / x.SpotPrice.Value) < 0.95 && x.BuySell == "卖出"))
|
|
{
|
|
tempTradeSpan.WorstCastClientPayable = tempTradeSpan.DeltaMargin = (0.15 + Math.Abs((eodPrice / x.SpotPrice.Value) - 1)) * eodPrice * x.TradeAmount;
|
|
}
|
|
else
|
|
{
|
|
tempTradeSpan.WorstCastClientPayable = tempTradeSpan.DeltaMargin = 0.15 * eodPrice * x.TradeAmount;
|
|
}
|
|
});
|
|
|
|
return resultMap.Values.Where(n => n.TradeId >= 0).ToList();
|
|
}
|
|
|
|
public override List<trade_span> CalcClientMargin(CalcClientMarginReq req)
|
|
{
|
|
var clientSpanNews = new List<ClientSpan>();
|
|
using (var db = new YLContext())
|
|
{
|
|
var underlyingCodes = req.tradeSpans.Select(t => t.UnderlyingCode).ToHashSet();
|
|
var mpProvider = new MarginParamProvider(req.UserInfo, req.settleDate).Initialize(underlyingCodes, MarginParamTypeEnum.MarginRate);
|
|
|
|
//删除
|
|
if (req.tradeSpans != null && req.tradeSpans.Count > 0)
|
|
{
|
|
var tradeIds = req.tradeSpans.Select(t => t.TradeId).ToList();
|
|
var tradeList = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList();
|
|
//var clientIds = req.tradeSpans.Select(t => t.ClientId).Distinct().ToList();
|
|
//var clientList = db.client.Where(x => clientIds.Contains(x.id)).ToList();
|
|
var tradeSpanInfos = (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 tradeSpanInfosWithoutDQ = tradeSpanInfos.Where(x => x.trade.StructureType != "掉期");
|
|
var tradeSpanInfosDQ = tradeSpanInfos.Where(x => x.trade.StructureType == "掉期");
|
|
|
|
var clientGroups = tradeSpanInfosWithoutDQ.GroupBy(t => t.trade.ClientId);
|
|
foreach (var clientGroup in clientGroups)
|
|
{
|
|
#region Span Margin Method
|
|
|
|
var underlyingGroup = clientGroup.GroupBy(t => t.trade.UnderlyingId).Select(t => new ClientSpan
|
|
{
|
|
UnderlyingId = 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 underlyingGroup)
|
|
{
|
|
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 tradeSpansUpdate = db.trade_span.Where(x => x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList();
|
|
if (item.WorstCastClientPayable == item.Spv1)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv1);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv2)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv3)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv4)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv5)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv5);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv6)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv6);
|
|
}
|
|
else
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv7);
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Delta Margin Method
|
|
|
|
var varietyGroup = clientGroup.GroupBy(t => t.tradeSpan.VarietyId).Select(t => new ClientSpan
|
|
{
|
|
VarietyId = t.Key,
|
|
ClientId = clientGroup.Key,
|
|
ValueDate = req.settleDate,
|
|
MaxMarginRate = t.Max(g => mpProvider.TryGetMarginRate(g.tradeSpan.UnderlyingCode, out var marginRate) ? marginRate : 0),
|
|
MaxSpotPrice = t.Max(g => g.tradeSpan.UnderlyingPrice),
|
|
PvForDelta = t.Sum(g => g.tradeSpan.Spv) * (-1),
|
|
DeltaSell = t.Sum(g => -g.tradeSpan.Delta * (g.trade.BuySell == "买入" || g.trade.TradeType == "远期" ? 1 : 0)),
|
|
DeltaBuy = t.Sum(g => -g.tradeSpan.Delta * (g.trade.BuySell == "卖出" && g.tradeSpan.Delta < 0 && g.trade.TradeType != "远期" ? 1 : 0)),
|
|
DeltaBuyMinus = t.Sum(g => -g.tradeSpan.Delta * (g.trade.BuySell == "卖出" && g.tradeSpan.Delta > 0 && g.trade.TradeType != "远期" ? 1 : 0)),
|
|
OptId = req.userId,
|
|
OptName = req.userName,
|
|
OptDate = DateTime.Now,
|
|
SpanType = req.SpanType
|
|
}).ToList();
|
|
|
|
foreach (var item in varietyGroup)
|
|
{
|
|
#region 更新tradeSpan,通过Delta品种级别求和算法,给tradeSpan的deltaMargin赋值
|
|
|
|
var tradeSpansUpdate = db.trade_span.Where(x => x.ClientId == item.ClientId && x.VarietyId == item.VarietyId && x.ValueDate == req.settleDate).ToList();
|
|
//DeltaSell为客户角度卖出,且为客户角度看Delta
|
|
if (item.DeltaSell > 0)
|
|
{
|
|
tradeSpansUpdate.ForEach(x =>
|
|
{
|
|
var tradeSpanInfo = tradeSpanInfosWithoutDQ.FirstOrDefault(y => y.trade.id == x.TradeId);
|
|
var trade = tradeSpanInfo != null ? tradeSpanInfo.trade : null;
|
|
//客户角度卖出的交易
|
|
//客户角度买入的交易,客户角度Delta<0,即交易员角度Delta>0
|
|
if (trade != null && (trade.BuySell == "买入" || trade.TradeType == "远期" || x.Delta > 0))
|
|
{
|
|
x.DeltaMargin = -x.Delta * item.MaxSpotPrice * item.MaxMarginRate + x.Spv;
|
|
}
|
|
});
|
|
item.DeltaMargin = -Math.Max((item.DeltaSell ?? 0) + (item.DeltaBuyMinus ?? 0), 0) * item.MaxSpotPrice * item.MaxMarginRate + item.PvForDelta;
|
|
}
|
|
else
|
|
{
|
|
tradeSpansUpdate.ForEach(x =>
|
|
{
|
|
var tradeSpanInfo = tradeSpanInfosWithoutDQ.FirstOrDefault(y => y.trade.id == x.TradeId);
|
|
var trade = tradeSpanInfo?.trade;
|
|
//客户角度卖出的交易
|
|
//客户角度买入的交易,客户角度Delta>0,即交易员角度Delta<0
|
|
if (trade != null && (trade.BuySell == "买入" || trade.TradeType == "远期" || x.Delta < 0))
|
|
{
|
|
x.DeltaMargin = x.Delta * item.MaxSpotPrice * item.MaxMarginRate + x.Spv;
|
|
}
|
|
});
|
|
item.DeltaMargin = Math.Min((item.DeltaSell ?? 0) + (item.DeltaBuy ?? 0), 0) * item.MaxSpotPrice * item.MaxMarginRate + item.PvForDelta;
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
#endregion
|
|
|
|
var clientSpan = new ClientSpan
|
|
{
|
|
ClientId = clientGroup.Key,
|
|
ValueDate = req.settleDate,
|
|
Spv1 = underlyingGroup.Sum(g => g.Spv1),
|
|
Spv2 = underlyingGroup.Sum(g => g.Spv2),
|
|
Spv3 = underlyingGroup.Sum(g => g.Spv3),
|
|
Spv4 = underlyingGroup.Sum(g => g.Spv4),
|
|
Spv5 = underlyingGroup.Sum(g => g.Spv5),
|
|
Spv6 = underlyingGroup.Sum(g => g.Spv6),
|
|
Spv7 = underlyingGroup.Sum(g => g.Spv7),
|
|
DeltaMargin = varietyGroup.Sum(g => g.DeltaMargin),
|
|
//负数代表客户应缴预付金,正数代表客户应收预付金
|
|
WorstCastClientPayable = underlyingGroup.Sum(g => g.WorstCastClientPayable) < 0 ? underlyingGroup.Sum(g => g.WorstCastClientPayable) : 0,
|
|
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 (clientSpan.WorstCastClientPayable > clientSpan.DeltaMargin)
|
|
{
|
|
clientSpan.WorstCastClientPayable = clientSpan.DeltaMargin;
|
|
|
|
//取delta预付金作为最终预付金
|
|
var tradeSpansUpdate = db.trade_span.Where(x => x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate).ToList();
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.DeltaMargin);
|
|
}
|
|
var worstCastClientPayableDQ = tradeSpanInfosDQ.Where(x => x.tradeSpan.ClientId == clientSpan.ClientId).Sum(x => x.tradeSpan.WorstCastClientPayable * -1);
|
|
clientSpan.WorstCastClientPayable += worstCastClientPayableDQ;
|
|
clientSpanNews.Add(clientSpan);
|
|
}
|
|
|
|
var clientIdsDQ = tradeSpanInfosDQ.Select(x => x.trade.ClientId).ToHashSet();
|
|
foreach (var clientId in clientIdsDQ)
|
|
{
|
|
if (!clientSpanNews.Select(x => x.ClientId).Contains(clientId))
|
|
{
|
|
var clientSpan = new ClientSpan
|
|
{
|
|
ClientId = clientId,
|
|
ValueDate = req.settleDate,
|
|
WorstCastClientPayable = 0,
|
|
OptId = req.userId,
|
|
OptName = req.userName,
|
|
OptDate = DateTime.Now,
|
|
SpanType = req.SpanType
|
|
};
|
|
|
|
var worstCastClientPayableDQ = tradeSpanInfosDQ.Where(x => x.tradeSpan.ClientId == clientId).Sum(x => x.tradeSpan.WorstCastClientPayable * -1);
|
|
clientSpan.WorstCastClientPayable += worstCastClientPayableDQ;
|
|
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 (tradeMargin != null && tradeMargin.FirstOrDefault() != null && trade.BuySell == "买入")
|
|
{
|
|
var margin = tradeMargin.FirstOrDefault().WorstCastClientPayable ?? 0.0;
|
|
var mpProvider = new MarginParamProvider(OptUserInfo.SystemUser, valuedateBLL.ValueDate.Date).Initialize(new List<string> { trade.UnderlyingCode }.ToHashSet(), MarginParamTypeEnum.MarginRate);
|
|
mpProvider.TryGetMarginRate(trade.UnderlyingCode, out var marginRate);
|
|
var deltaMargin = Math.Abs(tradeMargin.FirstOrDefault().Delta ?? 0) * (trade.SpotPrice ?? 0) * marginRate;
|
|
return margin > deltaMargin ? margin : deltaMargin;
|
|
}
|
|
return 0.0;
|
|
}
|
|
}
|
|
}
|