514 lines
30 KiB
C#
514 lines
30 KiB
C#
using YLErp.BLL.Calculation;
|
||
using YLErp.Enums;
|
||
using YLErp.Helpers;
|
||
using YLErp.Modules;
|
||
using YLErp.Modules.DataProviderModule;
|
||
using YLErp.Modules.MarginModule;
|
||
using YLErp.QdpModule;
|
||
|
||
namespace YLErp.BLL.MarginCalculation
|
||
{
|
||
/// <summary>
|
||
/// 格林大华
|
||
/// </summary>
|
||
public class GLDHMarginCalculation : MarginCalculationBase
|
||
{
|
||
// 定义一个静态变量来保存类的实例
|
||
public static readonly GLDHMarginCalculation Instance;
|
||
|
||
static GLDHMarginCalculation()
|
||
{
|
||
Instance = new GLDHMarginCalculation();
|
||
}
|
||
|
||
// 定义私有构造函数,使外界不能创建该类实例
|
||
private GLDHMarginCalculation()
|
||
{
|
||
}
|
||
|
||
public override List<trade_span> RunMarginCalculation(RunMarginCalculationReq req)
|
||
{
|
||
var resultList = new List<trade_span>();
|
||
|
||
if (req.CalcMarginType == Enums.CalcMarginTypeEnum.InitialMargin)
|
||
{
|
||
resultList = calcInitialMargin(req);
|
||
}
|
||
else
|
||
{
|
||
resultList = calcPositionMargin(req);
|
||
}
|
||
|
||
|
||
return resultList;
|
||
}
|
||
/// <summary>
|
||
/// 初始预付金
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
/// <returns></returns>
|
||
private List<trade_span> calcInitialMargin(RunMarginCalculationReq req)
|
||
{
|
||
Dictionary<int, trade_span> resultMap = new Dictionary<int, trade_span>();
|
||
var _helper = new RunMarginCalculationHelper(req, _underlyingDataProvider);
|
||
var marginProvider = _helper.GetMarginParamProvider(Modules.MarginModule.MarginParamTypeEnum.MarginRate);
|
||
|
||
var tradeTypes = new List<string>() { "远期", "收益互换" };
|
||
var forword = req.tradeList.Where(O => O.TradeType == "远期");
|
||
foreach (var item in forword)
|
||
{
|
||
var margin =
|
||
item.Notional * (item.SpotPrice ?? 0)
|
||
* (marginProvider.TryGetMarginRate(item.UnderlyingCode, out var m) ? m : 0);
|
||
var sp = _helper.CreateTradeSpan(item).SetAllSpvAndWorst(margin);
|
||
LogFactory.GetLogger<MarginCalculationBase>().Debug($"{margin}={item.Notional}*{item.SpotPrice}* {(marginProvider.TryGetMarginRate(item.UnderlyingCode, out var ms) ? ms : 0)})");
|
||
|
||
sp.SetWorstCastClientPayable();
|
||
|
||
resultMap[sp.TradeId] = sp;
|
||
}
|
||
|
||
var swap = req.tradeList.Where(O => O.TradeType == "收益互换");
|
||
tradeBLL.SetFieldsByTradeType(swap);
|
||
foreach (var item in swap)
|
||
{
|
||
var rate = (item.trade_swap?.GetMarginRate ?? 0) - (item.trade_swap?.PayMarginRate ?? 0);
|
||
var margin = 0d;
|
||
if (rate > 0)
|
||
{
|
||
margin =
|
||
item.StockEqvNotional
|
||
* rate;
|
||
var client = DataCacheProvider.GetClientDataSource().GetData(item.ClientId);
|
||
var clientLevel = DataCacheProvider.GetClientLevelDataSource().GetData(client.LevelId ?? 0);
|
||
var clientRatio = clientLevel?.Ratio ?? 1.0;
|
||
margin *= clientRatio;
|
||
}
|
||
var sp = _helper.CreateTradeSpan(item).SetAllSpvAndWorst(margin);
|
||
sp.SetWorstCastClientPayable();
|
||
|
||
resultMap[sp.TradeId] = sp;
|
||
}
|
||
|
||
|
||
//所有客户买入的交易都不收取预付金,包含买入单腿,跨式期权,风险反转期权以及其他多腿组合期权(买入牛市价差或熊市价差时,卖出的那条腿也不收取预付金)
|
||
var sellList = req.tradeList.Where(O => !tradeTypes.Contains(O.TradeType) && O.BuySell == "卖出");
|
||
foreach (var item in sellList)
|
||
{
|
||
var sp = _helper.CreateTradeSpan(item).SetAllSpvAndWorst(0);
|
||
sp.SetWorstCastClientPayable();
|
||
resultMap[sp.TradeId] = sp;
|
||
}
|
||
|
||
var buyList = req.tradeList.Where(O => !tradeTypes.Contains(O.TradeType) && !resultMap.Keys.Contains(O.id));
|
||
var calcReq =
|
||
_helper.GetCalculateRisksForTradesReq(
|
||
req.PriceProvider,
|
||
null,
|
||
null,
|
||
Qdp.Pricing.Base.Implementations.PricingRequest.Delta);
|
||
calcReq.tradeList = buyList;
|
||
var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq);
|
||
|
||
//客户卖出跨式期权
|
||
//初始预付金 = max(D1,D2)×S×交易所期货预付金率×数量;
|
||
//其中 D1,D2 分别为跨式期权两腿的 Delta 绝对值。
|
||
var tradeIds = buyList.Where(O => (O.StructureType ?? O.TradeType).Contains("跨式") && O.BuySell == "买入").Select(O => O.id);
|
||
var resultDict = tradeRiskResult.Results.Where(O => tradeIds.Contains(O.Trade.id)).GroupBy(O => O.Trade.ParentTradeId).ToDictionary(K => K.Key, V => V.ToList());
|
||
foreach (var item in resultDict)
|
||
{
|
||
var margin =
|
||
item.Value
|
||
.Max(O => Math.Abs(O.ValueResult.DeltaCash)
|
||
* (marginProvider.TryGetMarginRate(O.Trade.UnderlyingCode, out var m) ? m : 0));
|
||
var sp = _helper.CreateTradeSpan(item.Value[0].Trade).SetAllSpvAndWorst(margin);
|
||
sp.SetWorstCastClientPayable();
|
||
resultMap[item.Value[0].Trade.id] = sp;
|
||
for (int i = 1; i < item.Value.Count; i++)
|
||
{
|
||
sp = _helper.CreateTradeSpan(item.Value[i].Trade).SetAllSpvAndWorst(0);
|
||
sp.SetWorstCastClientPayable();
|
||
resultMap[item.Value[i].Trade.id] = sp;
|
||
}
|
||
}
|
||
|
||
//客户卖出单腿期权
|
||
//初始预付金 = D×S×交易所期货预付金率×数量;
|
||
tradeIds = buyList.Where(O => !((O.StructureType ?? O.TradeType).Contains("跨式")) && O.BuySell == "买入").Select(O => O.id);
|
||
var resultList = tradeRiskResult.Results.Where(O => tradeIds.Contains(O.Trade.id));
|
||
resultList.ToList().ForEach(O =>
|
||
{
|
||
var margin = Math.Abs(O.ValueResult.DeltaCash * (marginProvider.TryGetMarginRate(O.Trade.UnderlyingCode, out var m) ? m : 0));
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info("初始预付金 = D×S×交易所期货预付金率×数量;");
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"{margin}=Math.Abs({O.ValueResult.DeltaCash} * {(marginProvider.TryGetMarginRate(O.Trade.UnderlyingCode, out var ms) ? ms : 0)})");
|
||
var sp = _helper.CreateTradeSpan(O.Trade).SetAllSpvAndWorst(margin);
|
||
sp.SetWorstCastClientPayable();
|
||
resultMap[sp.TradeId] = sp;
|
||
});
|
||
|
||
return resultMap.Values.ToList();
|
||
}
|
||
/// <summary>
|
||
/// 计算每笔预付金
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
/// <returns></returns>
|
||
private List<trade_span> calcPositionMargin(RunMarginCalculationReq req)
|
||
{
|
||
var resultMap = new Dictionary<int, trade_span>();
|
||
var tradeTypes = new List<string>() { "远期", "收益互换" };
|
||
//结算s
|
||
req.PriceProvider = new EodPriceProvider(req.settleDate).GetPriceProvider(SettlementTypeEnum.SettlePrice);
|
||
//收盘
|
||
var closePriceProvider = new EodPriceProvider(req.settleDate).GetPriceProvider(SettlementTypeEnum.ClosePrice);
|
||
var _helper = new RunMarginCalculationHelper(req, _underlyingDataProvider);
|
||
var marginProvider = _helper.GetMarginParamProvider(Modules.MarginModule.MarginParamTypeEnum.MarginRate);
|
||
//获取涨跌停价格字典
|
||
_helper.GetUpDownLimitPrices(out var upPrices, out var downPrices);
|
||
//获取持仓波动率字典
|
||
_helper.GetUpDownVolRateDic(out var upVolRateDic, out _);
|
||
|
||
var clientGroup = req.tradeList.GroupBy(O => new { O.ClientId, O.UnderlyingCode }).ToDictionary(K => K.Key, V => V.ToList());
|
||
foreach (var item in clientGroup)
|
||
{
|
||
var forword = req.tradeList.Where(O => O.TradeType == "远期");
|
||
foreach (var t in forword)
|
||
{
|
||
var margin =
|
||
t.Notional * (t.SpotPrice ?? 0)
|
||
* (marginProvider.TryGetMarginRate(t.UnderlyingCode, out var m) ? m : 0);
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"该交易{t.TradeNumber}id{t.id};远期" +
|
||
$"{margin} ={t.Notional * (t.SpotPrice ?? 0) * (marginProvider.TryGetMarginRate(t.UnderlyingCode, out var s) ? s : 0)}");
|
||
|
||
var sp = _helper.CreateTradeSpan(t).SetAllSpvAndWorst(margin);
|
||
sp.SetWorstCastClientPayable();
|
||
resultMap[sp.TradeId] = sp;
|
||
}
|
||
var swap = req.tradeList.Where(O => O.TradeType == "收益互换");
|
||
tradeBLL.SetFieldsByTradeType(swap);
|
||
foreach (var t in swap)
|
||
{
|
||
var rate = (t.trade_swap?.GetMarginRate ?? 0) - (t.trade_swap?.PayMarginRate ?? 0);
|
||
var margin = 0d;
|
||
if (rate > 0)
|
||
{
|
||
margin =
|
||
t.StockEqvNotional
|
||
* (marginProvider.TryGetMarginRate(t.UnderlyingCode, out var m) ? m : 0);
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"该交易{t.TradeNumber}id{t.id}收益互换{margin}");
|
||
|
||
|
||
var client = DataCacheProvider.GetClientDataSource().GetData(t.ClientId);
|
||
var clientLevel = DataCacheProvider.GetClientLevelDataSource().GetData(client.LevelId ?? 0);
|
||
var clientRatio = clientLevel?.Ratio ?? 1.0;
|
||
margin *= clientRatio;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"该交易 margin *= clientRatio {t.TradeNumber} id{t.id}收益互换{margin}");
|
||
}
|
||
var sp = _helper.CreateTradeSpan(t).SetAllSpvAndWorst(margin);
|
||
sp.SetWorstCastClientPayable();
|
||
resultMap[sp.TradeId] = sp;
|
||
}
|
||
/*计算总维持预付金时,先分标的计算,再进行汇总计算。
|
||
* 如果客户在标的 i 上只有买权合约,则该标的不计入预付金计算范围;
|
||
* 如果客户在在标的 i 上有卖权合约,则该标的的所有合约都纳入预付金计算范围。
|
||
*/
|
||
var option = item.Value.Where(O => !tradeTypes.Contains(O.TradeType));
|
||
if (option.All(O => O.BuySell == "卖出"))
|
||
{
|
||
foreach (var t in option)
|
||
{
|
||
var sp = _helper.CreateTradeSpan(t).SetAllSpvAndWorst(0);
|
||
sp.SetWorstCastClientPayable();
|
||
resultMap[sp.TradeId] = sp;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
var prices = new Dictionary<int, Dictionary<string, double>>();
|
||
var umCodeList = option.Select(O => O.UnderlyingCode).ToHashSet();
|
||
foreach (var code in umCodeList)
|
||
{
|
||
prices[1] = new Dictionary<string, double>();
|
||
prices[2] = new Dictionary<string, double>();
|
||
prices[3] = new Dictionary<string, double>();
|
||
prices[4] = new Dictionary<string, double>();
|
||
prices[5] = new Dictionary<string, double>();
|
||
prices[6] = new Dictionary<string, double>();
|
||
prices[7] = new Dictionary<string, double>();
|
||
prices[8] = new Dictionary<string, double>();
|
||
var upPrice = upPrices.GetPrice(code);
|
||
var downPrice = downPrices.GetPrice(code);
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"涨跌价格:{upPrice} {downPrice}");
|
||
var interval = (upPrice - downPrice) / 6;
|
||
|
||
var settlePrice = req.PriceProvider.GetPrice(code);
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"settlePrice:{settlePrice} interval:=(upPrice - downPrice) / 6={interval}={(upPrice - downPrice)} / {6}");
|
||
prices[1][code] = settlePrice - 3 * interval;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林持仓预付金1:prices[1][{code}] = settlePrice - 3 * interval;{prices[1][code]}={settlePrice}- 3 * {interval}");
|
||
prices[2][code] = settlePrice - 2 * interval;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林持仓预付金2:prices[2][{code}] = settlePrice - 2 * interval:{prices[2][code]}={settlePrice}- 2 * {interval}");
|
||
prices[3][code] = settlePrice - 1 * interval;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林持仓预付金3:prices[3][{code}] = settlePrice - 1 * interval:{prices[3][code]}={settlePrice}- 1 * {interval}");
|
||
prices[4][code] = settlePrice;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林持仓预付金4:prices[4][{code}] = settlePrice:{prices[4][code] = settlePrice}");
|
||
prices[5][code] = settlePrice + 1 * interval;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林持仓预付金5:prices[5][{code}] = settlePrice - 1 * interval:{prices[5][code]}={settlePrice}+ 1 * {interval}");
|
||
prices[6][code] = settlePrice + 2 * interval;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林持仓预付金6:prices[6][{code}] = settlePrice - 2 * interval:{prices[6][code]}={settlePrice}+ 2 * {interval}");
|
||
prices[7][code] = settlePrice + 3 * interval;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林持仓预付金7:prices[7][{code}] = settlePrice - 3 * interval:{prices[7][code]} ={settlePrice}+3 * {interval}");
|
||
prices[8][code] = closePriceProvider.GetPrice(code);
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林持仓预付金8收盘价算Detal:{prices[8][code] = closePriceProvider.GetPrice(code)}");
|
||
}
|
||
foreach (var p in prices)
|
||
{
|
||
var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(
|
||
valueDate: req.settleDate,
|
||
calcScenario: req.GetCalcScenario(),
|
||
tradeList: item.Value,
|
||
priceProvider: new ManualPriceProvider(p.Value),
|
||
pricingRequest: QdpPricingRequest.BASIC_PRICING,
|
||
addVolRateDic: p.Key < 8 ? upVolRateDic : null, //1~7为PM,波动率应当上浮,第8个为DM,波动率不用变化
|
||
volType: req.volType,
|
||
isUseTradeVol: PS.Config.IsTradeVol,
|
||
preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin,
|
||
isAddVolPercent: true);
|
||
foreach (var risk in tradeRiskResult.Results)
|
||
{
|
||
var code = risk.Trade.UnderlyingCode;
|
||
var pric = p.Value[risk.Trade.UnderlyingCode];
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林持仓预付金该交易编号:{risk.Trade.TradeNumber} id:{risk.Trade.id}标的:{code} 交易价格为:{pric}");
|
||
if (!resultMap.TryGetValue(risk.Trade.id, out var tradeSpan))
|
||
{
|
||
resultMap[risk.Trade.id] = tradeSpan = _helper.CreateTradeSpan(risk.Trade);
|
||
}
|
||
|
||
switch (p.Key)
|
||
{
|
||
case 1:
|
||
tradeSpan.Spv1 = risk.ValueResult.Pv;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林持仓预付金该交易的PV1为:{tradeSpan.Spv1}");
|
||
break;
|
||
case 2:
|
||
tradeSpan.Spv2 = risk.ValueResult.Pv;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林持仓预付金该交易的PV2为:{tradeSpan.Spv2}");
|
||
break;
|
||
case 3:
|
||
tradeSpan.Spv3 = risk.ValueResult.Pv;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林持仓预付金该交易的PV3为:{tradeSpan.Spv3}");
|
||
break;
|
||
case 4:
|
||
tradeSpan.Spv4 = risk.ValueResult.Pv;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林持仓预付金该交易的PV4为:{tradeSpan.Spv4}");
|
||
break;
|
||
case 5:
|
||
tradeSpan.Spv5 = risk.ValueResult.Pv;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林持仓预付金该交易的PV5为:{tradeSpan.Spv5}");
|
||
break;
|
||
case 6:
|
||
tradeSpan.Spv6 = risk.ValueResult.Pv;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林持仓预付金该交易的PV6为:{tradeSpan.Spv6}");
|
||
break;
|
||
case 7:
|
||
tradeSpan.Spv7 = risk.ValueResult.Pv;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林持仓预付金该交易的PV7为:{tradeSpan.Spv7}");
|
||
break;
|
||
case 8:
|
||
tradeSpan.Spv8 = risk.ValueResult.Pv;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林持仓预付金该交易的PV8为:{tradeSpan.Spv8}");
|
||
tradeSpan.DeltaMargin = risk.ValueResult.DeltaCash;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
//第八个pv不参与pm计算
|
||
if (p.Key < 8)
|
||
{
|
||
tradeSpan.SetWorstCastClientPayable();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return resultMap.Values.ToList();
|
||
}
|
||
|
||
/// <summary>
|
||
/// 计算每个客户预付金
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
/// <returns></returns>
|
||
public override List<trade_span> CalcClientMargin(CalcClientMarginReq req)
|
||
{
|
||
var clientSpanNews = new List<ClientSpan>();
|
||
var _mpProvider = new MarginParamProvider(req.UserInfo, req.settleDate);
|
||
|
||
using (var db = new YLContext())
|
||
{
|
||
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 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 umCode = tradeList.Select(O => O.UnderlyingCode).ToHashSet();
|
||
var marginProvider = _mpProvider.Initialize(umCode, MarginParamTypeEnum.MarginRate);
|
||
|
||
var clientGroups = tradeSpanInfo.GroupBy(t => t.trade.ClientId);
|
||
foreach (var item in clientGroups)
|
||
{
|
||
var tradeTypes = new List<string>() { "远期", "收益互换" };
|
||
var forword = item.Where(O => O.trade.TradeType == "远期");
|
||
var swap = item.Where(O => O.trade.TradeType == "收益互换");
|
||
|
||
var worstCastClientPayable_forward = -forword.Sum(O => O.tradeSpan.WorstCastClientPayable ?? 0);
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林维持预付金远期为:{worstCastClientPayable_forward}");
|
||
var worstCastClientPayable_swap = -swap.Sum(O => O.tradeSpan.WorstCastClientPayable ?? 0);
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林维持预付金收益互换为:{worstCastClientPayable_swap}");
|
||
var worstCastClientPayable_option = 0d;
|
||
|
||
var option = item.Where(O => !tradeTypes.Contains(O.trade.TradeType));
|
||
if (option.Any(O => O.trade.BuySell == "买入"))
|
||
{
|
||
var dm = option.Sum(O =>
|
||
{
|
||
var margin = (marginProvider.TryGetMarginRate(O.trade.UnderlyingCode, out var m) ? m : 0);
|
||
var a = Math.Abs((O.tradeSpan.DeltaMargin ?? 0) * margin) - O.tradeSpan.Spv8 ?? 0;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林维持保证的dm为:{a}");
|
||
return Math.Abs((O.tradeSpan.DeltaMargin ?? 0) * margin) - O.tradeSpan.Spv8 ?? 0;
|
||
});
|
||
|
||
dm = Math.Max(dm, 0);
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林维持保证最大的dm:{dm}");
|
||
//计算标的 i 在上 7 种情形下客户持仓的持仓价值 MVi,k(k=1,2,3…7)(客户卖出期权,期权价值取负值),
|
||
//则客户在标的 i 上隔日最大亏损 Li = -min(Vi,k),对第 i 个标的取维持预付金 PMi = Max(Li,0);
|
||
//var pm = option.GroupBy(O => O.trade.UnderlyingCode).Sum(O => Math.Max(O.Sum(B => B.tradeSpan.WorstCastClientPayable ?? 0), 0));
|
||
var underlyingGroup = option.GroupBy(O => O.trade.UnderlyingCode);
|
||
var pmList = new List<double>();
|
||
foreach (var unItem in underlyingGroup)
|
||
{
|
||
var list = new List<double>()
|
||
{
|
||
unItem.Sum(O => O.tradeSpan.Spv1??0),
|
||
unItem.Sum(O => O.tradeSpan.Spv2??0),
|
||
unItem.Sum(O => O.tradeSpan.Spv3??0),
|
||
unItem.Sum(O => O.tradeSpan.Spv4??0),
|
||
unItem.Sum(O => O.tradeSpan.Spv5??0),
|
||
unItem.Sum(O => O.tradeSpan.Spv6??0),
|
||
unItem.Sum(O => O.tradeSpan.Spv7??0),
|
||
}; LogFactory.GetLogger<MarginCalculationBase>().Info($"格林维持预付金 7 种情形下客户持仓值为1:" +
|
||
$"{unItem.Sum(O => O.tradeSpan.Spv1 ?? 0)}" +
|
||
" 2:" + $"{unItem.Sum(O => O.tradeSpan.Spv2 ?? 0)}" +
|
||
" 3:" + $"{unItem.Sum(O => O.tradeSpan.Spv3 ?? 0)}" +
|
||
" 4:" + $"{unItem.Sum(O => O.tradeSpan.Spv4 ?? 0)}" +
|
||
" 5:" + $"{unItem.Sum(O => O.tradeSpan.Spv5 ?? 0)}" +
|
||
" 6:" + $"{unItem.Sum(O => O.tradeSpan.Spv6 ?? 0)}" +
|
||
" 7:" + $"{unItem.Sum(O => O.tradeSpan.Spv7 ?? 0)} 代码角度若为卖出期权则为负数(-min)所以最小的加-则为正数");
|
||
var pmi = list.Max(O => O);
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林维持预付金PM为Max(Li,0){pmi}");
|
||
pmList.Add(pmi);
|
||
}
|
||
|
||
var pm = pmList.Sum();
|
||
|
||
worstCastClientPayable_option = Math.Max(dm, pm);
|
||
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林维持保证标的i维持预付金M=Max(dm,pm){worstCastClientPayable_option}={Math.Max(dm, pm)}");
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"格林维持保证标的i维持预付金M=Max(dm,pm){worstCastClientPayable_option}");
|
||
#region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致
|
||
|
||
var sumDelta = option.Sum(O => Math.Abs(O.tradeSpan.DeltaMargin ?? 0));
|
||
tradeIds = option.Select(x => x.trade.id).ToList();
|
||
var tradeSpansUpdate = db.trade_span.Where(x => tradeIds.Contains(x.TradeId) && x.ClientId == item.Key && x.ValueDate == req.settleDate).ToList();
|
||
var tradeSpansReq = req.tradeSpans.Where(x => tradeIds.Contains(x.TradeId) && x.ClientId == item.Key && x.ValueDate == req.settleDate).ToList();
|
||
|
||
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = worstCastClientPayable_option * Math.Abs(x.DeltaMargin ?? 0) / sumDelta);
|
||
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = worstCastClientPayable_option * Math.Abs(x.DeltaMargin ?? 0) / sumDelta);
|
||
|
||
#endregion
|
||
}
|
||
var worstCastClientPayable = -worstCastClientPayable_option + worstCastClientPayable_forward + worstCastClientPayable_swap;
|
||
LogFactory.GetLogger<MarginCalculationBase>().Info($"{worstCastClientPayable = -worstCastClientPayable_option + worstCastClientPayable_forward + worstCastClientPayable_swap}");
|
||
var clientSpan = new ClientSpan
|
||
{
|
||
ClientId = item.Key,
|
||
ValueDate = req.settleDate,
|
||
Spv1 = worstCastClientPayable,
|
||
Spv2 = worstCastClientPayable,
|
||
Spv3 = worstCastClientPayable,
|
||
Spv4 = worstCastClientPayable,
|
||
//负数代表客户应缴预付金,正数代表客户应收预付金
|
||
WorstCastClientPayable = worstCastClientPayable,
|
||
SwapWorstCastClientPayable = worstCastClientPayable_swap,
|
||
MySideMargin = worstCastClientPayable,
|
||
OptId = req.userId,
|
||
OptName = req.userName,
|
||
OptDate = DateTime.Now,
|
||
SpanType = req.SpanType,
|
||
AdditionalWorstCastClientPayable = req.clientAdditionalMarginDic != null
|
||
&& req.clientAdditionalMarginDic.TryGetValue(item.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)}={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.client_span.AddRange(clientSpanNews);
|
||
}
|
||
db.SaveChanges();
|
||
}
|
||
return req.tradeSpans;
|
||
}
|
||
public override double GetTradeMargin(GetTradeMarginReq req)
|
||
{
|
||
var trade = req.trade;
|
||
using (YLContext 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)
|
||
{
|
||
return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0;
|
||
}
|
||
return 0.0;
|
||
}
|
||
}
|
||
}
|