334 lines
18 KiB
C#
334 lines
18 KiB
C#
using Qdp.Pricing.Library.Base.Utilities;
|
|
using System.Linq;
|
|
using YLErp.Abstract.DataProviders;
|
|
using YLErp.BLL.Calculation;
|
|
using YLErp.Enums;
|
|
using YLErp.Helpers;
|
|
using YLErp.Model.Enum;
|
|
using YLErp.Modules.ApiModule;
|
|
using YLErp.Modules.CalculationModule;
|
|
using YLErp.Modules.DataProviderModule;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.BLL.MarginCalculation
|
|
{
|
|
/// <summary>
|
|
/// 广期资本
|
|
/// </summary>
|
|
public class GQMarginCalculation : MarginCalculationBase
|
|
{
|
|
// 定义一个静态变量来保存类的实例
|
|
public static readonly GQMarginCalculation Instance;
|
|
|
|
static GQMarginCalculation()
|
|
{
|
|
Instance = new GQMarginCalculation();
|
|
}
|
|
// 定义私有构造函数,使外界不能创建该类实例
|
|
protected GQMarginCalculation()
|
|
{
|
|
|
|
}
|
|
public override List<trade_span> RunMarginCalculation(RunMarginCalculationReq req)
|
|
{
|
|
var resultMap = new List<trade_span>();
|
|
resultMap.AddRange(marginCalculation(req));
|
|
return resultMap;
|
|
}
|
|
/// <summary>
|
|
/// 计算同一交易
|
|
/// </summary>
|
|
/// <param name="req"></param>
|
|
/// <returns></returns>
|
|
private List<trade_span> marginCalculation(RunMarginCalculationReq req)
|
|
{
|
|
//结果集
|
|
var resultMap = new Dictionary<int, trade_span>();
|
|
var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider);
|
|
//var mpProvider = helper.GetMarginParamProvider(MarginParamTypeEnum.MarginRate | MarginParamTypeEnum.UpDownLimit);
|
|
//为了算客户角度的一个预付金数值
|
|
helper.ReverseTradeSide();
|
|
helper.SetFieldsByTradeType();
|
|
//取出张跌停价格
|
|
helper.GetUpDownLimitPrices(out var upLimitPrices, out var downLimitPrices);
|
|
//up涨停价 //down跌停价 //normal期权价
|
|
var prices = new (string, IPriceProvider)[] { ("up", upLimitPrices), ("down", downLimitPrices), ("normal", req.PriceProvider) };//期初价格
|
|
|
|
foreach (var price in prices)
|
|
{
|
|
var key = $"{price.Item1}";
|
|
//计算交易风险指标 计算Pv
|
|
var tradeRiskResult2 = CalculatorHelper.CalculateRisksForTrades(
|
|
valueDate: req.settleDate,
|
|
tradeList: req.tradeList,
|
|
calcScenario: req.GetCalcScenario(),//日终持仓预付金
|
|
priceProvider: price.Item2,//计算接口期初价格
|
|
pricingRequest: QdpPricingRequest.PV_ONLY,
|
|
addVolRateDic: null,
|
|
volType: req.volType,
|
|
isUseTradeVol: PS.Config.IsTradeVol,
|
|
preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin,
|
|
isAddVolPercent: false);
|
|
|
|
if (tradeRiskResult2.Results == null || tradeRiskResult2.Results.Count < 1)
|
|
{
|
|
continue;
|
|
}
|
|
foreach (var item in tradeRiskResult2.Results)
|
|
{
|
|
//var client= helper.GetClient(item.Trade.ClientId);
|
|
//获取交易值和span
|
|
var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan);
|
|
var value = item.ValueResult.Pv;
|
|
if (!contains)
|
|
{
|
|
resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade);
|
|
}
|
|
switch (key)
|
|
{
|
|
//算出三个pv
|
|
case "up":
|
|
tempTradeSpan.Spv1 = value;
|
|
break;
|
|
case "normal":
|
|
tempTradeSpan.Spv2 = value;
|
|
tempTradeSpan.Comment += " normal:" + item.ValueResult.Pv.ToString() + " ;";
|
|
break;
|
|
case "down":
|
|
tempTradeSpan.Spv3 = value;
|
|
tempTradeSpan.Comment += " down:" + item.ValueResult.Pv.ToString() + " ;";
|
|
break;
|
|
}
|
|
// tempTradeSpan.Spv4 = item.Trade.TradePrice;
|
|
double key_up = 0;
|
|
double key_down = 0;
|
|
//该笔交易涨跌停盈亏为卖出并且期初权利金为0
|
|
if (contains && item.Trade.BuySell == "卖出" && item.Trade.TradePrice != 0)
|
|
{
|
|
key_up = Math.Max((tempTradeSpan.Spv1 ?? 0) - (tempTradeSpan.Spv2 ?? 0), 0);
|
|
logger.Info($"该交易;{item.Trade.TradeNumber} 價格:{price.Item2.GetPrice(item.Trade.UnderlyingCode)} 卖出并且期初权利金不为0涨盈亏为:{key_up} PV1-PV{tempTradeSpan.Spv1}-{tempTradeSpan.Spv2}");
|
|
}
|
|
else
|
|
{
|
|
key_up = (tempTradeSpan.Spv1 ?? 0) - (tempTradeSpan.Spv2 ?? 0);
|
|
logger.Info($"该交易;{item.Trade.TradeNumber} 價格:{price.Item2.GetPrice(item.Trade.UnderlyingCode)} 涨盈亏为:{key_up} PV1-PV{tempTradeSpan.Spv1}-{tempTradeSpan.Spv2}");
|
|
}
|
|
//跌停盈亏
|
|
if (contains && item.Trade.BuySell == "卖出" && item.Trade.TradePrice != 0)
|
|
{
|
|
key_down = Math.Max((tempTradeSpan.Spv3 ?? 0) - (tempTradeSpan.Spv2 ?? 0), 0);
|
|
logger.Info($"该交易;{item.Trade.TradeNumber} 價格:{price.Item2.GetPrice(item.Trade.UnderlyingCode)} 卖出并且期初权利金不为0跌盈亏为:{key_down} PV-PV2{tempTradeSpan.Spv2}-{tempTradeSpan.Spv3} ");
|
|
}
|
|
else
|
|
{
|
|
key_down = (tempTradeSpan.Spv3 ?? 0) - (tempTradeSpan.Spv2 ?? 0);
|
|
logger.Info($"该交易;{item.Trade.TradeNumber} 價格:{price.Item2.GetPrice(item.Trade.UnderlyingCode)} 跌盈亏为:{key_down} PV-PV2{tempTradeSpan.Spv2}-{tempTradeSpan.Spv3} ");
|
|
}
|
|
tempTradeSpan.WorstCastClientPayable = Math.Max(key_up, key_down);
|
|
LogFactory.GetLogger("涨跌盈亏最大").Info(tempTradeSpan.WorstCastClientPayable.ToString());
|
|
}
|
|
}
|
|
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>();
|
|
using (var db = new YLContext())
|
|
{
|
|
if (req.tradeSpans != null && req.tradeSpans.Count > 0)
|
|
{
|
|
var trades = req.tradeSpans;
|
|
var clientGroups = req.tradeSpans.GroupBy(t => t.ClientId);
|
|
foreach (var clientGroup in clientGroups)
|
|
{
|
|
var underlyingMarginDic = new Dictionary<string, double?[]>();
|
|
var vIds = clientGroup.Select(o => o.VarietyId).Distinct();//所有品种
|
|
//计算出所有标的pv
|
|
foreach (var ts in clientGroup)
|
|
{
|
|
var td = trades.FirstOrDefault(o => o.id == ts.TradeId);
|
|
var key = ts.UnderlyingCode + "_" + ts.VarietyId.ToString();// + "_" + td.BuySell;标的 ///VarietyId品种ID
|
|
if (!underlyingMarginDic.ContainsKey(key))
|
|
{
|
|
underlyingMarginDic.Add(key, new double?[3] { ts.Spv1, ts.Spv2, ts.Spv3 });
|
|
}
|
|
else
|
|
{
|
|
var us = underlyingMarginDic[key];
|
|
us[0] += ts.Spv1;
|
|
us[1] += ts.Spv2;
|
|
us[2] += ts.Spv3;
|
|
}
|
|
}
|
|
//标的层面的盈亏
|
|
var underlyingMargins = new Dictionary<string, double>();
|
|
var VarietyMarginsByUpDown = new Dictionary<string, double>();
|
|
var VarietyMargins = new Dictionary<string, double>();
|
|
foreach (var item in underlyingMarginDic)
|
|
{
|
|
var uvCode = item.Key;
|
|
var key_up = uvCode + "_up";
|
|
//uvCode.Split('_')[0] + "_" + uvCode.Split('_')[1]
|
|
var key_down = uvCode + "_down";
|
|
if (!underlyingMargins.ContainsKey(key_up))
|
|
{
|
|
//与0相比取最大
|
|
underlyingMargins.Add(key_up, Math.Max((item.Value[0] ?? 0) - (item.Value[1] ?? 0), 0));
|
|
LogFactory.GetLogger("标的合约下所有的盈利合计= pv1-pv").Info($"{underlyingMargins.Values.ToString()}={(item.Value[0] ?? 0)} -{(item.Value[1] ?? 0)},0)");
|
|
}
|
|
if (!underlyingMargins.ContainsKey(key_down))
|
|
{
|
|
//与0相比
|
|
underlyingMargins.Add(key_down, Math.Max((item.Value[2] ?? 0) - (item.Value[1] ?? 0), 0));
|
|
LogFactory.GetLogger("标的合约下所有的亏损合计= pv-pv2").Info($"{underlyingMargins.Values.ToString()}={(item.Value[1] ?? 0)} -{(item.Value[2] ?? 0)},0)");
|
|
}
|
|
}
|
|
//计算同一客户单品标的合约盈亏累计的和 A00_Id_up/down
|
|
foreach (var item in underlyingMargins)
|
|
{
|
|
//品种 标的id盈亏
|
|
var uvCode = item.Key;
|
|
var vId = uvCode.Split('_')[1];
|
|
var upDown = uvCode.Split('_')[2];
|
|
vId = vId + upDown;
|
|
if (VarietyMarginsByUpDown.ContainsKey(vId))
|
|
{
|
|
//所有盈亏累加
|
|
VarietyMarginsByUpDown[vId] += item.Value;
|
|
LogFactory.GetLogger("计算同一客户单品盈亏总和累计").Info(VarietyMarginsByUpDown[vId].ToString());
|
|
}
|
|
else
|
|
{
|
|
VarietyMarginsByUpDown.Add(vId, item.Value);
|
|
LogFactory.GetLogger("1计算同一客户单品盈亏总和累计").Info(VarietyMarginsByUpDown[vId].ToString());
|
|
}
|
|
}
|
|
//根据客户涨跌停品种取出合计
|
|
foreach (var item in vIds)
|
|
{
|
|
var upCode = item.ToString() + "up";
|
|
var downCode = item.ToString() + "down";
|
|
try
|
|
{
|
|
var upMargin = VarietyMarginsByUpDown[upCode];
|
|
var downMargin = VarietyMarginsByUpDown[downCode];
|
|
if (!VarietyMargins.ContainsKey(item.ToString()))
|
|
{
|
|
//取最大
|
|
VarietyMargins.Add(item.ToString(), Math.Max(upMargin, downMargin));
|
|
LogFactory.GetLogger("客户涨跌停盈亏分别为:").Info($"{upMargin},{downMargin}");
|
|
LogFactory.GetLogger("根据客户涨跌停品种判断取出合计").Info(VarietyMargins.Values.ToString());
|
|
}
|
|
}
|
|
catch (Exception)
|
|
{
|
|
VarietyMargins.Add(item.ToString(), 0);
|
|
}
|
|
}
|
|
|
|
foreach (var item in VarietyMargins)
|
|
{
|
|
if (int.TryParse(item.Key, out int varietyId))
|
|
{
|
|
//根据品种
|
|
var varietyGroup = clientGroup.Where(o => o.VarietyId == varietyId);
|
|
//var tradePricedic = trades.GroupBy(l => new { l.ClientId }).(tradePricedic.Where(t => t.kv == ts.VarietyId && t.kc == ts.ClientId).FirstOrDefault()?.v) ?item.Value : 0;
|
|
//Select(s => new { kc = s.Key.ClientId, v = Math.Min(s.Sum(item.Key) ?? 0,0) });
|
|
var t = 0;
|
|
foreach (var ts in varietyGroup)
|
|
{
|
|
//所有单客户品种所有标的期初取最小 //因为不与单客户收支比较因此取客户涨停盈亏合计
|
|
// var sh = Math.Max(varietyGroup.Sum(s => s.Spv4) ?? 0, 0);
|
|
//单品种维持预付金
|
|
var aa = item.Value; //> sh ? item.Value : 0;
|
|
var dbts = db.trade_span.FirstOrDefault(o => o.id == ts.id);
|
|
if (dbts != null)
|
|
{
|
|
dbts.WorstCastClientPayable = t == 0 ? aa : 0;//将多笔交易放到一笔交易
|
|
logger.Info($"单客户涨跌停品种盈亏合计为{aa}");
|
|
}
|
|
var dbts1 = req.tradeSpans.FirstOrDefault(o => o.id == ts.id);
|
|
dbts1.WorstCastClientPayable = t == 0 ? aa : 0;
|
|
t++;
|
|
}
|
|
}
|
|
}
|
|
//所有品种维持预付金加总
|
|
var clientSpan = new ClientSpan
|
|
{
|
|
ClientId = clientGroup.Key ?? 0,
|
|
ValueDate = req.settleDate,
|
|
//负数代表客户应缴预付金,正数代表客户应收预付金
|
|
WorstCastClientPayable = req.tradeSpans.Where(O => O.ClientId == (clientGroup.Key ?? 0)).Sum(O => O.WorstCastClientPayable ?? 0) * -1,
|
|
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
|
|
};
|
|
LogFactory.GetLogger("该客户当日维持预付金所有预付金总和:").Info(clientSpan.ToString());
|
|
LogFactory.GetLogger("该客户当日维持预付金所有预付金VarietyMargins总和:").Info(clientSpan.VariationMargin.ToString());
|
|
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();
|
|
clientSpanNews = clientSpanNews.Where(c => !clientSpanOldsWithFlag.Any(t => t.ValueDate == c.ValueDate && t.ClientId == c.ClientId)).ToList();
|
|
}
|
|
if (clientSpanNews.Count > 0)
|
|
{
|
|
db.client_span.AddRange(clientSpanNews);
|
|
}
|
|
db.SaveChanges();
|
|
return req.tradeSpans;
|
|
}
|
|
}
|
|
public override double GetTradeMargin(GetTradeMarginReq req)
|
|
{
|
|
using (var db = new YLContext())
|
|
{
|
|
if (req.trade.TradeType == "结构化交易")
|
|
{
|
|
req.trade.SubTrades = db.trade.Where(x => x.ParentTradeId == req.trade.id).ToList();
|
|
}
|
|
}
|
|
var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq());
|
|
if (null != tradeMargin)
|
|
{
|
|
return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0;
|
|
}
|
|
return 0.0;
|
|
}
|
|
}
|
|
}
|