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

319 lines
13 KiB
C#

using YLErp.BLL.Calculation;
using YLErp.Enums;
using YLErp.Modules.MarginModule;
using YLErp.Modules.VolatilityModule;
using YLErp.QdpModule;
namespace YLErp.BLL.MarginCalculation
{
public class MaoChuanMarginCalculation : MarginCalculationBase
{
// 定义一个静态变量来保存类的实例(单例模式)
public static readonly MaoChuanMarginCalculation Instance;
static MaoChuanMarginCalculation()
{
Instance = new MaoChuanMarginCalculation();
}
// 定义私有构造函数,使外界不能创建该类实例
private MaoChuanMarginCalculation()
{
}
/// <summary>
/// 计算香草期权和亚式期权预付金
/// </summary>
private List<trade_span> CalculationNormalOptionMargin(RunMarginCalculationReq req)
{
var resultMap = new Dictionary<int, trade_span>();
var codes = req.tradeList.Select(O => O.UnderlyingCode).ToHashSet();
var mpProvider = new MarginParamProvider(req.UserInfo, req.settleDate)
.Initialize(codes, MarginParamTypeEnum.MarginRate);
//客户要求用AskVol计算预付金,所以先把所有交易方向改为卖出并把VolType赋值为 BidAskVol;
//Dictionary<int, string> buySellDict = tradeList.ToDictionary(K => K.id, V => V.BuySell);
//tradeList.ForEach(t => t.BuySell = "卖出");
var vols = new Dictionary<int, double>();
foreach (var t in req.tradeList)
{
var vType = t.VolType;
t.VolType = "报价Ask";
var um = _underlyingDataProvider.GetUnderlying(t.UnderlyingCode);
if (um == null)
{
throw new MarginCalcException($"[预付金计算]找不到标的数据(交易编号:{t.TradeNumber},标的代码:{t.UnderlyingCode})");
}
var vol = SingleVolService.GetSingleVol(new SingleVolReq(t, um), req.userId, isEodCalc: req.CalcMarginType == CalcMarginTypeEnum.EodMargin);
vols[t.id] = vol;
t.VolType = vType;
}
var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(
valueDate: req.settleDate,
tradeList: req.tradeList,
calcScenario: CalcScenarioEnum.EodSettlement,
priceProvider: req.PriceProvider,
pricingRequest: QdpPricingRequest.BASIC_PRICING,
addVolRateDic: null,
volType: null,
overrideVolsForTrade: vols,
isUseTradeVol: PS.Config.IsTradeVol,
preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin);
//tradeList.ForEach(t => t.BuySell = buySellDict[t.id]);
foreach (var r in tradeRiskResult.Results)
{
if (!mpProvider.TryGetMarginRate(r.Trade.UnderlyingCode, out var marginRate))
{
throw new MarginCalcException($"{r.Trade.UnderlyingCode} 预付金比率不存在");
}
var trade = req.tradeList.FirstOrDefault(t => t.id == r.Trade.id);
if (!req.PriceProvider.TryGetPrice(r.Trade.UnderlyingCode, out var price))
{
price = r.Trade.SpotPrice ?? 0;
}
logger.Info($"茂川标准预付金计算:[{r.Trade.TradeType}_{r.Trade.BuySell}_{r.Trade.OptionType}_{r.Trade.Strike}] => Vol:{r.ValueResult.Vol};Delta:{r.ValueResult.Delta}");
//预付金= Delta*标的期货预付金比率*标的期货价格*持仓规模 (qdp计算出的Delta已经乘过数量了,所以这里不用再乘了);
var value = Math.Abs(r.ValueResult.Delta) * marginRate * price;// * r.Trade.Notional;
if (r.Trade.BuySell == "买入") { value = Math.Abs(value); } else { value = 0 - Math.Abs(value); }
var tempTradeSpan = new trade_span
{
TradeId = r.Trade.id,
ClientId = trade.ClientId,
ValueDate = req.settleDate,
UnderlyingId = trade.UnderlyingId,
UnderlyingCode = trade.UnderlyingCode,
OptId = req.userId,
OptName = req.userName,
OptDate = DateTime.Now,
Spv1 = value,
Spv2 = value,
Spv3 = value,
Spv4 = value,
WorstCastClientPayable = value
};
resultMap[r.Trade.id] = tempTradeSpan;
}
return resultMap.Values.ToList();
}
/// <summary>
/// 计算其他期权预付金
/// </summary>
private List<trade_span> CalculationOtherOptionMargin(RunMarginCalculationReq req)
{
var resultMap = new Dictionary<int, trade_span>();
var tempTradeList = new List<trade>();
var vols = new Dictionary<int, double>();
foreach (var t in req.tradeList)
{
var vType = t.VolType;
t.VolType = "报价Ask";
var um = _underlyingDataProvider.GetUnderlying(t.UnderlyingCode);
var vol = SingleVolService.GetSingleVol(new SingleVolReq(t, um), req.userId, req.CalcMarginType == CalcMarginTypeEnum.EodMargin);
vols[t.id] = vol;
t.VolType = vType;
tempTradeList.Add(t.Clone());
}
var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(
valueDate: req.settleDate,
tradeList: tempTradeList,
calcScenario: CalcScenarioEnum.EodSettlement,
priceProvider: req.PriceProvider,
pricingRequest: QdpPricingRequest.BASIC_PRICING,
addVolRateDic: null,
volType: null,
overrideVolsForTrade: vols,
isUseTradeVol: PS.Config.IsTradeVol,
preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin);
//if (priceDict == null)
//{
// priceDict = new Dictionary<int, double>();
// Dictionary<int, string[]> rateDict = base.GetUpDownLimitRate(req.tradeList.Select(O => O.UnderlyingId).ToArray());
// tempTradeList.ForEach(t =>
// {
// double[] arr = base.GetUpDownLimitPrice(rateDict[t.id], (t.SpotPrice ?? 0), double.Parse(rateDict[t.id][2]));
// priceDict[t.UnderlyingId] = t.OptionType == "看涨" ? arr[1] : arr[0];
// });
//}
//else
//{
// Dictionary<int, double[]> dict = base.GetUpDownLimitPrice(priceDict);
// tempTradeList.ForEach(t =>
// priceDict[t.UnderlyingId] = t.OptionType == "看涨" ? dict[t.id][1] : dict[t.id][0]);
//}
var newTradeRiskResult = CalculatorHelper.CalculateRisksForTrades(
valueDate: req.settleDate,
tradeList: tempTradeList,
calcScenario: CalcScenarioEnum.EodSettlement,
priceProvider: req.PriceProvider,
pricingRequest: QdpPricingRequest.BASIC_PRICING,
addVolRateDic: null,
volType: null,
overrideVolsForTrade: vols,
isUseTradeVol: PS.Config.IsTradeVol,
preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin);
foreach (var t in tempTradeList)
{
var cPv = tradeRiskResult.Results.FirstOrDefault(O => O.ValueResult.TradeId == t.id).ValueResult.Pv;
var nPv = newTradeRiskResult.Results.FirstOrDefault(O => O.ValueResult.TradeId == t.id).ValueResult.Pv;
//预付金= 次日最大亏损;
var value = t.OptionType == "看涨" ? cPv - nPv : cPv + nPv;
logger.Info($"茂川奇异预付金计算:[{t.TradeType}_{t.BuySell}_{t.OptionType}_{t.Strike}] => 当日Pv:{cPv};次日Pv:{nPv}");
var tempTradeSpan = new trade_span
{
TradeId = t.id,
ClientId = t.ClientId,
ValueDate = req.settleDate,
UnderlyingId = t.UnderlyingId,
UnderlyingCode = t.UnderlyingCode,
OptId = req.userId,
OptName = req.userName,
OptDate = DateTime.Now,
Spv1 = value,
Spv2 = value,
Spv3 = value,
Spv4 = value,
WorstCastClientPayable = value
};
resultMap[t.id] = tempTradeSpan;
}
return resultMap.Values.ToList();
}
private List<trade_span> CalculationStructureOptionMargin(RunMarginCalculationReq req)
{
var resultMap = new List<trade_span>();
foreach (var td in req.tradeList)
{
var tempId = int.MaxValue;
td.SubTrades.ToList().ForEach(t => t.id = tempId--);
var childrenSpans = RunMarginCalculation(req.Clone(td.SubTrades.ToList()));
double margin = 0;
switch (td.StructureType)
{
case "牛市价差":
case "熊市价差":
case "亚式熊市价差":
case "三领口组合":
for (var j = 0; j < childrenSpans.Count; j++)
{
margin += childrenSpans[j].WorstCastClientPayable ?? 0;
}
break;
case "跨式组合":
case "宽跨式组合":
for (var j = 0; j < childrenSpans.Count; j++)
{
var absMargin = Math.Abs(childrenSpans[j].WorstCastClientPayable ?? 0);
if (margin < absMargin)
{
margin = absMargin;
}
}
break;
case "复制标的资产":
case "蝶式组合":
case "飞鹰式组合":
case "比例价差":
case "日历价差":
case "箱式价差":
case "风险逆转":
default:
break;
}
var tempTradeSpan = 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 = margin,
Spv2 = margin,
Spv3 = margin,
Spv4 = margin,
WorstCastClientPayable = margin
};
resultMap.Add(tempTradeSpan);
}
return resultMap;
}
public override List<trade_span> RunMarginCalculation(RunMarginCalculationReq req)
{
var resultMap = new List<trade_span>();
if (req.tradeList == null || !req.tradeList.Any())
{
return resultMap;
}
if (req.forOtherSide)
{
return RunMarginCalculationOtherSide(req);
}
var tList = req.tradeList.Where(O => O.TradeType == "结构化交易").ToList();
if (tList.Count > 0)
{
resultMap.AddRange(CalculationStructureOptionMargin(req.Clone(tList)));
}
tList = req.tradeList.Where(O => O.TradeType == "香草期权" || O.TradeType == "亚式期权").ToList();
if (tList.Count > 0)
{
resultMap.AddRange(CalculationNormalOptionMargin(req.Clone(tList)));
}
tList = req.tradeList.Where(O => O.TradeType != "结构化交易" && O.TradeType != "香草期权" && O.TradeType != "亚式期权").ToList();
if (tList.Count > 0)
{
resultMap.AddRange(CalculationOtherOptionMargin(req.Clone(tList)));
}
return resultMap;
}
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;
}
}
}