328 lines
16 KiB
C#
328 lines
16 KiB
C#
using YLErp.BLL.Calculation;
|
|
using YLErp.Enums;
|
|
using YLErp.Model.Enum;
|
|
using YLErp.Modules.CalculationModule;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.BLL.MarginCalculation
|
|
{
|
|
public class HongYeMarginCalculation : MarginCalculationBase
|
|
{
|
|
//定义一个静态变量来保存类的实例(单例模式)
|
|
public static readonly HongYeMarginCalculation Instance;
|
|
|
|
static HongYeMarginCalculation()
|
|
{
|
|
Instance = new HongYeMarginCalculation();
|
|
}
|
|
|
|
//定义私有构造函数,使外界不能创建该类实例
|
|
private HongYeMarginCalculation()
|
|
{
|
|
}
|
|
|
|
public override List<trade_span> RunMarginCalculation(RunMarginCalculationReq req)
|
|
{
|
|
if (req.tradeList == null || !req.tradeList.Any())
|
|
{
|
|
return new List<trade_span>();
|
|
}
|
|
return CalcMargin(req).ToList();
|
|
}
|
|
|
|
|
|
private IEnumerable<trade_span> CalcMargin(RunMarginCalculationReq req)
|
|
{
|
|
var resultMap = new Dictionary<int, trade_span>();
|
|
var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider);
|
|
|
|
//为了算客户角度的一个预付金数值
|
|
helper.ReverseTradeSide();
|
|
|
|
helper.SetFieldsByTradeType();
|
|
|
|
var calcReq = helper.GetCalculateRisksForTradesReq(req.PriceProvider, null, null, QdpPricingRequest.BASIC_PRICING);
|
|
|
|
switch (req.CalcMarginType)
|
|
{
|
|
case CalcMarginTypeEnum.InitialMargin:
|
|
calcReq.volType = "开仓";
|
|
calcReq.isUseTradeVol = false;
|
|
break;
|
|
case CalcMarginTypeEnum.None:
|
|
case CalcMarginTypeEnum.EodMargin:
|
|
default:
|
|
calcReq.volType = "交易";
|
|
calcReq.isUseTradeVol = true;
|
|
break;
|
|
}
|
|
|
|
var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(calcReq);
|
|
foreach (var item in tradeRiskResult.Results)
|
|
{
|
|
resultMap[item.Trade.id] = generateTradeSpan(
|
|
(resultMap.ContainsKey(item.Trade.id) ? resultMap[item.Trade.id] : null),
|
|
item,
|
|
helper,
|
|
req);
|
|
}
|
|
|
|
var structureIds = new List<int>();
|
|
var tDict =
|
|
(from r in tradeRiskResult.Results
|
|
join ts in resultMap
|
|
on r.Trade.id equals ts.Key
|
|
where r.Trade.TradeType == "结构化交易" ||
|
|
r.Trade.ParentTradeId != 0
|
|
group new { r, ts } by r.Trade.ParentTradeId into rGroup
|
|
select rGroup).ToDictionary(K => K.First().r.Trade, V => V.ToList());
|
|
|
|
if (tDict.Count > 0)
|
|
{
|
|
foreach (var structureItem in tDict)
|
|
{
|
|
var client = GetClientInfo(structureItem.Key.ClientId);
|
|
var direction = structureItem.Value.Select(O => O.r.Trade.BuySell).ToHashSet();
|
|
double value = 0;
|
|
var index = 0;
|
|
if ((structureItem.Key.StructureType == "牛市价差" || structureItem.Key.StructureType == "熊市价差") && structureItem.Value.Count >= 2)
|
|
{
|
|
if (client != null && (MarginOptionEnum)client.MarginOptionType == MarginOptionEnum.单向追保)
|
|
{
|
|
var buyLeg = structureItem.Value.Where(O => O.r.Trade.BuySell == "买入").FirstOrDefault();
|
|
var buyMargin = (buyLeg?.ts.Value.WorstCastClientPayable) ?? 0;
|
|
foreach (var item in structureItem.Value)
|
|
{
|
|
setTradeSpanValue(item.ts.Value, 0);
|
|
}
|
|
if (structureItem.Value.Sum(O => O.r.ValueResult.Pv) > 0)
|
|
{
|
|
var strikes = structureItem.Value.Select(O => ((O.r.Trade.IsMoneynessOption == "是" ? (O.r.Trade.SpotPrice * O.r.Trade.Strike) : O.r.Trade.Strike) ?? 0)).ToArray();
|
|
value = Math.Abs((strikes[0] - strikes[1]) * structureItem.Key.Notional);
|
|
setTradeSpanValue(buyLeg.ts.Value, Math.Min(value, buyMargin));
|
|
}
|
|
}
|
|
else if (client != null && (MarginOptionEnum)client.MarginOptionType == MarginOptionEnum.对手方单向追保)
|
|
{
|
|
var sellLeg = structureItem.Value.Where(O => O.r.Trade.BuySell == "卖出").FirstOrDefault();
|
|
var sellMargin = (sellLeg?.ts.Value.WorstCastClientPayable) ?? 0;
|
|
foreach (var item in structureItem.Value)
|
|
{
|
|
setTradeSpanValue(item.ts.Value, 0);
|
|
}
|
|
if (structureItem.Value.Sum(O => O.r.ValueResult.Pv) < 0)
|
|
{
|
|
var strikes = structureItem.Value.Select(O => ((O.r.Trade.IsMoneynessOption == "是" ? (O.r.Trade.SpotPrice * O.r.Trade.Strike) : O.r.Trade.Strike) ?? 0)).ToArray();
|
|
value = Math.Abs((strikes[0] - strikes[1]) * structureItem.Key.Notional);
|
|
setTradeSpanValue(sellLeg.ts.Value, Math.Min(value, sellMargin));
|
|
}
|
|
}
|
|
}
|
|
else if (structureItem.Key.StructureType.Contains("跨式") && structureItem.Value.Count == 2)
|
|
{
|
|
var minLeg = structureItem.Value[1];
|
|
if (Math.Abs(structureItem.Value[0].r.ValueResult.Delta) < Math.Abs(structureItem.Value[1].r.ValueResult.Delta))
|
|
{
|
|
minLeg = structureItem.Value[0];
|
|
}
|
|
setTradeSpanValue(minLeg.ts.Value, minLeg.r.ValueResult.Pv);
|
|
}
|
|
else
|
|
{
|
|
if (client != null)
|
|
{
|
|
switch ((MarginOptionEnum)client.MarginOptionType)
|
|
{
|
|
case MarginOptionEnum.对手方单向追保:
|
|
if (direction.Count == 1)
|
|
{
|
|
value = double.MaxValue;
|
|
//最小值
|
|
for (var i = 0; i < structureItem.Value.Count; i++)
|
|
{
|
|
if (value > structureItem.Value[i].ts.Value.WorstCastClientPayable)
|
|
{
|
|
index = i;
|
|
value = structureItem.Value[i].ts.Value.WorstCastClientPayable ?? 0;
|
|
}
|
|
setTradeSpanValue(structureItem.Value[i].ts.Value, 0);
|
|
structureIds.Add(structureItem.Value[i].ts.Key);
|
|
}
|
|
setTradeSpanValue(structureItem.Value[index].ts.Value, value);
|
|
}
|
|
break;
|
|
case MarginOptionEnum.单向追保:
|
|
case MarginOptionEnum.双向追保:
|
|
default:
|
|
if (direction.Count == 1)
|
|
{
|
|
value = double.MinValue;
|
|
//最大值
|
|
for (var i = 0; i < structureItem.Value.Count; i++)
|
|
{
|
|
if (value < structureItem.Value[i].ts.Value.WorstCastClientPayable)
|
|
{
|
|
index = i;
|
|
value = structureItem.Value[i].ts.Value.WorstCastClientPayable ?? 0;
|
|
}
|
|
setTradeSpanValue(structureItem.Value[i].ts.Value, 0);
|
|
structureIds.Add(structureItem.Value[i].ts.Key);
|
|
}
|
|
setTradeSpanValue(structureItem.Value[index].ts.Value, value);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (direction.Count == 1)
|
|
{
|
|
value = double.MinValue;
|
|
//最大值
|
|
for (var i = 0; i < structureItem.Value.Count; i++)
|
|
{
|
|
if (value < structureItem.Value[i].ts.Value.WorstCastClientPayable)
|
|
{
|
|
index = i;
|
|
value = structureItem.Value[i].ts.Value.WorstCastClientPayable ?? 0;
|
|
}
|
|
setTradeSpanValue(structureItem.Value[i].ts.Value, 0);
|
|
structureIds.Add(structureItem.Value[i].ts.Key);
|
|
}
|
|
setTradeSpanValue(structureItem.Value[index].ts.Value, value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var tList = (from r in tradeRiskResult.Results
|
|
join ts in resultMap
|
|
on r.Trade.id equals ts.Key
|
|
where !structureIds.Contains(r.Trade.id)
|
|
select new { r, ts }).ToList();
|
|
|
|
if (tList.Count > 0)
|
|
{
|
|
foreach (var item in tList)
|
|
{
|
|
double value = 0;
|
|
var client = GetClientInfo(item.r.Trade.ClientId);
|
|
if (client != null)
|
|
{
|
|
switch ((MarginOptionEnum)client.MarginOptionType)
|
|
{
|
|
case MarginOptionEnum.单向追保:
|
|
value = item.ts.Value.WorstCastClientPayable ?? 0;
|
|
value = Math.Max(value, 0);
|
|
break;
|
|
case MarginOptionEnum.对手方单向追保:
|
|
value = item.ts.Value.WorstCastClientPayable ?? 0;
|
|
value = Math.Max(value, 0);
|
|
break;
|
|
case MarginOptionEnum.双向追保:
|
|
default:
|
|
value = item.ts.Value.WorstCastClientPayable ?? 0;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
value = item.ts.Value.WorstCastClientPayable ?? 0;
|
|
}
|
|
item.ts.Value.Spv1 = value;
|
|
item.ts.Value.Spv2 = value;
|
|
item.ts.Value.Spv3 = value;
|
|
item.ts.Value.Spv4 = value;
|
|
item.ts.Value.SetWorstCastClientPayable();
|
|
}
|
|
}
|
|
return resultMap.Values.ToList();
|
|
}
|
|
|
|
private trade_span generateTradeSpan(trade_span trade_Span, TradeRiskResultRecord record, RunMarginCalculationHelper helper, RunMarginCalculationReq req)
|
|
{
|
|
if (trade_Span == null)
|
|
{
|
|
trade_Span = helper.CreateTradeSpan(record.Trade);
|
|
}
|
|
|
|
var client = GetClientInfo(record.Trade.ClientId);
|
|
double value;
|
|
if (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin && record.Trade.TradeType == "收益互换")
|
|
{
|
|
var pnl = record.Trade.trade_swap.GetTradePrice.GetValueOrDefault() - record.Trade.trade_swap.PayTradePrice.GetValueOrDefault() - record.ValueResult.Pv;
|
|
helper.GetSpecialMargin(record.Trade, pnl, out value);
|
|
}
|
|
else if (record.Trade.TradeType == "远期" || record.Trade.TradeType == "收益互换")
|
|
{
|
|
var marginRate = helper.GetMarginParamProvider().GetMarginRate(record.Trade.UnderlyingCode) ?? 0;
|
|
var price = req.PriceProvider.GetPrice(record.Trade.UnderlyingCode);
|
|
value = price * marginRate * record.Trade.Notional + Math.Max((record.ValueResult.Pv - record.Trade.TradePrice ?? 0), 0);
|
|
}
|
|
else
|
|
{
|
|
var marginRate = helper.GetMarginParamProvider().GetMarginRate(record.Trade.UnderlyingCode) ?? 0;
|
|
var price = req.PriceProvider.GetPrice(record.Trade.UnderlyingCode);
|
|
var delta = Math.Abs(record.ValueResult.Delta);
|
|
if (record.ValueResult.Pv < 0)
|
|
{
|
|
delta = -delta;
|
|
}
|
|
if (HasTwoSideMargin(record.Trade.ClientId))
|
|
{
|
|
value = record.ValueResult.Pv + delta * marginRate * price;
|
|
}
|
|
else if (!helper.GetSpecialMargin(record.Trade, 0, out value))
|
|
{
|
|
double ratio;
|
|
switch (req.CalcMarginType)
|
|
{
|
|
case CalcMarginTypeEnum.InitialMargin:
|
|
ratio = client?.Ratio1 ?? 1;
|
|
break;
|
|
case CalcMarginTypeEnum.None:
|
|
case CalcMarginTypeEnum.EodMargin:
|
|
default:
|
|
ratio = client?.Ratio ?? 1;
|
|
break;
|
|
}
|
|
value = record.ValueResult.Pv + ratio * delta * marginRate * price;
|
|
}
|
|
}
|
|
trade_Span.Spv1 = value;
|
|
trade_Span.Spv2 = value;
|
|
trade_Span.Spv3 = value;
|
|
trade_Span.Spv4 = value;
|
|
trade_Span.SetWorstCastClientPayable();
|
|
return trade_Span;
|
|
}
|
|
|
|
private void setTradeSpanValue(trade_span obj, double value)
|
|
{
|
|
obj.Spv1 = value;
|
|
obj.Spv2 = value;
|
|
obj.Spv3 = value;
|
|
obj.Spv4 = value;
|
|
obj.SetWorstCastClientPayable();
|
|
}
|
|
|
|
public override double GetTradeMargin(GetTradeMarginReq req)
|
|
{
|
|
var trade = req.trade;
|
|
if (trade.TradeType == "结构化交易" && (trade.SubTrades == null || trade.SubTrades.Count() == 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;
|
|
}
|
|
}
|
|
}
|