675 lines
30 KiB
C#
675 lines
30 KiB
C#
using YLErp.Abstract.DataProviders;
|
|
using YLErp.BLL.Calculation;
|
|
using YLErp.Enums;
|
|
using YLErp.Helpers;
|
|
using YLErp.Modules;
|
|
using YLErp.Modules.CalculationModule;
|
|
using YLErp.Modules.DataCacheModule;
|
|
using YLErp.Modules.DataProviderModule;
|
|
using YLErp.Modules.MarginModule;
|
|
using YLErp.Modules.UnderlyingModule;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.BLL.MarginCalculation
|
|
{
|
|
/// <summary>
|
|
/// 方顿
|
|
/// </summary>
|
|
public class FDMarginCalculation : MarginCalculationBase
|
|
{
|
|
// 定义一个静态变量来保存类的实例
|
|
public static readonly FDMarginCalculation Instance;
|
|
|
|
static FDMarginCalculation()
|
|
{
|
|
Instance = new FDMarginCalculation();
|
|
}
|
|
|
|
// 定义私有构造函数,使外界不能创建该类实例
|
|
private FDMarginCalculation()
|
|
{
|
|
|
|
}
|
|
|
|
public override List<trade_span> RunMarginCalculation(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();
|
|
|
|
GetPrices(req, out var TPrices1, out var TPrices2, out var TPrices3, out var TPrices4, out var TPrices5, out var TPrices6, out var TPrices7, out var TPrices8, out var TPrices9, out var TPrices10, out var TPrices11, out var TPrices12, out var TPrices13, out var TPrices14);
|
|
|
|
var prices = new (string pId, IPriceProvider provider)[] { ("pr1", TPrices1), ("pr2", TPrices2), ("pr3", TPrices3), ("pr4", TPrices4), ("pr5", TPrices5), ("pr6", TPrices6), ("pr7", TPrices7), ("pr8", TPrices8), ("pr9", TPrices9), ("pr10", TPrices10), ("pr11", TPrices11), ("pr12", TPrices12), ("pr13", TPrices13), ("pr14", TPrices14) };
|
|
|
|
var priceProvider = new ManualPriceProvider();
|
|
|
|
foreach (var price in prices)
|
|
{
|
|
var key = $"{price.Item1}";
|
|
var Results = req.tradeList.SelectMany(t =>
|
|
{
|
|
priceProvider.SetPrice(t.UnderlyingCode, price.provider.GetPrice(t.id.ToString()));
|
|
var tradeRiskResult1 = CalculatorHelper.CalculateRisksForTrades(
|
|
valueDate: req.settleDate,
|
|
calcScenario: req.GetCalcScenario(),
|
|
tradeList: new[] { t },
|
|
priceProvider: priceProvider,
|
|
pricingRequest: QdpPricingRequest.PV_ONLY,
|
|
addVolRateDic: null,
|
|
volType: req.volType,
|
|
isUseTradeVol: PS.Config.IsTradeVol,
|
|
preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin,
|
|
isAddVolPercent: false);
|
|
return (tradeRiskResult1.Results?.AsEnumerable()) ?? Enumerable.Empty<TradeRiskResultRecord>();
|
|
});
|
|
|
|
if (!Results.Any())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
foreach (var item in Results)
|
|
{
|
|
var client = helper.GetClient(item.Trade.ClientId);
|
|
|
|
var clientRatio = client == null ? 1.0 : client?.Ratio ?? 1.0;
|
|
var clientRatio1 = client == null ? 1.0 : client?.Ratio1 ?? 1.0;
|
|
|
|
var contains = resultMap.TryGetValue(item.Trade.id, out var tempTradeSpan);
|
|
|
|
var pv = item.ValueResult.Pv;
|
|
|
|
if (!helper.GetSpecialMargin(item.Trade, pv, out var value))
|
|
{
|
|
if (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin)
|
|
{
|
|
value = double.IsNaN(pv) ? 0 : pv * clientRatio1;
|
|
}
|
|
else
|
|
{
|
|
value = double.IsNaN(pv) ? 0 : pv;
|
|
}
|
|
}
|
|
|
|
if (!contains)
|
|
{
|
|
resultMap[item.Trade.id] = tempTradeSpan = helper.CreateTradeSpan(item.Trade);
|
|
}
|
|
|
|
switch (key)
|
|
{
|
|
case "pr1":
|
|
tempTradeSpan.Spv1 = value; break;
|
|
case "pr2":
|
|
tempTradeSpan.Spv2 = value; break;
|
|
case "pr3":
|
|
tempTradeSpan.Spv3 = value; break;
|
|
case "pr4":
|
|
tempTradeSpan.Spv4 = value; break;
|
|
case "pr5":
|
|
tempTradeSpan.Spv5 = value; break;
|
|
case "pr6":
|
|
tempTradeSpan.Spv6 = value; break;
|
|
case "pr7":
|
|
tempTradeSpan.Spv7 = value; break;
|
|
case "pr8":
|
|
tempTradeSpan.Spv8 = value; break;
|
|
case "pr9":
|
|
tempTradeSpan.Spv9 = value; break;
|
|
case "pr10":
|
|
tempTradeSpan.Spv10 = value; break;
|
|
case "pr11":
|
|
tempTradeSpan.Spv11 = value; break;
|
|
case "pr12":
|
|
tempTradeSpan.Spv12 = value; break;
|
|
case "pr13":
|
|
tempTradeSpan.Spv13 = value; break;
|
|
case "pr14":
|
|
tempTradeSpan.Spv14 = value; break;
|
|
}
|
|
|
|
if (contains)
|
|
{
|
|
tempTradeSpan.SetWorstCastClientPayable();
|
|
}
|
|
}
|
|
}
|
|
|
|
return resultMap.Values.ToList();
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取T0,T1涨跌停价格字典 ----方顿
|
|
/// 涨跌停板幅度 T0 d1 T1 涨停 (1+d1)*(1+d1)-1 跌停 1-(1-d1)*(1-d1)
|
|
/// </summary>
|
|
public void GetPrices(RunMarginCalculationReq req, out IPriceProvider TPrices1, out IPriceProvider TPrices2, out IPriceProvider TPrices3, out IPriceProvider TPrices4, out IPriceProvider TPrices5, out IPriceProvider TPrices6, out IPriceProvider TPrices7, out IPriceProvider TPrices8, out IPriceProvider TPrices9, out IPriceProvider TPrices10, out IPriceProvider TPrices11, out IPriceProvider TPrices12, out IPriceProvider TPrices13, out IPriceProvider TPrices14)
|
|
{
|
|
|
|
var _TPrices1 = new ManualPriceProvider();
|
|
var _TPrices2 = new ManualPriceProvider();
|
|
var _TPrices3 = new ManualPriceProvider();
|
|
var _TPrices4 = new ManualPriceProvider();
|
|
var _TPrices5 = new ManualPriceProvider();
|
|
var _TPrices6 = new ManualPriceProvider();
|
|
var _TPrices7 = new ManualPriceProvider();
|
|
var _TPrices8 = new ManualPriceProvider();
|
|
var _TPrices9 = new ManualPriceProvider();
|
|
var _TPrices10 = new ManualPriceProvider();
|
|
var _TPrices11 = new ManualPriceProvider();
|
|
var _TPrices12 = new ManualPriceProvider();
|
|
var _TPrices13 = new ManualPriceProvider();
|
|
var _TPrices14 = new ManualPriceProvider();
|
|
|
|
//根据涨跌幅限制以及当日结算价计算涨停价以及跌停价
|
|
foreach (var item in req.tradeList)
|
|
{
|
|
var code = item.UnderlyingCode;
|
|
|
|
var price = req.PriceProvider.GetPrice(code);
|
|
|
|
var pricenow = GetUnderlyingPrice(code, req.UserInfo, req.settleDate);
|
|
|
|
if (req.CalcMarginType == CalcMarginTypeEnum.InitialMargin)
|
|
{
|
|
price = pricenow;
|
|
}
|
|
else if (req.CalcMarginType == CalcMarginTypeEnum.None)
|
|
{
|
|
if (item.TradeDate?.ToString("yyyyMMdd") == req.settleDate.ToString("yyyyMMdd"))
|
|
{
|
|
price = pricenow;
|
|
}
|
|
else
|
|
{
|
|
price = (price + pricenow) / 2;
|
|
}
|
|
}
|
|
|
|
var _mpProvider = new MarginParamProvider(req.UserInfo, req.settleDate);
|
|
if (_mpProvider.TryGetUpdownLimit(code, out var limit, out var isFixed))
|
|
{
|
|
if (isFixed)
|
|
{
|
|
limit /= price;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
limit = 0.05;
|
|
}
|
|
|
|
//注意:price价格可能为负值
|
|
limit = Math.Abs(limit);
|
|
|
|
double upPrice;
|
|
double downPrice;
|
|
|
|
var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider);
|
|
var client = helper.GetClient(item.ClientId);
|
|
|
|
if (client == null)
|
|
{
|
|
upPrice = price * (1 + limit);
|
|
downPrice = price * (1 - limit);
|
|
}
|
|
else
|
|
{
|
|
if (string.IsNullOrWhiteSpace(client.RuleT0orT1) || client.RuleT0orT1 == "T+0")
|
|
{
|
|
upPrice = price * (1 + limit);
|
|
downPrice = price * (1 - limit);
|
|
}
|
|
else
|
|
{
|
|
var a1 = (1 + limit) * (1 + limit) - 1;
|
|
var a2 = 1 - (1 - limit) * (1 - limit);
|
|
upPrice = price * (1 + a1);
|
|
downPrice = price * (1 - a2);
|
|
}
|
|
}
|
|
|
|
var p1 = downPrice + (upPrice - downPrice) * 1 / 13;
|
|
var p2 = downPrice + (upPrice - downPrice) * 2 / 13;
|
|
var p3 = downPrice + (upPrice - downPrice) * 3 / 13;
|
|
var p4 = downPrice + (upPrice - downPrice) * 4 / 13;
|
|
var p5 = downPrice + (upPrice - downPrice) * 5 / 13;
|
|
var p6 = downPrice + (upPrice - downPrice) * 6 / 13;
|
|
var p7 = downPrice + (upPrice - downPrice) * 7 / 13;
|
|
var p8 = downPrice + (upPrice - downPrice) * 8 / 13;
|
|
var p9 = downPrice + (upPrice - downPrice) * 9 / 13;
|
|
var p10 = downPrice + (upPrice - downPrice) * 10 / 13;
|
|
var p11 = downPrice + (upPrice - downPrice) * 11 / 13;
|
|
var p12 = downPrice + (upPrice - downPrice) * 12 / 13;
|
|
|
|
_TPrices1.SetPrice(item.id.ToString(), downPrice);
|
|
_TPrices2.SetPrice(item.id.ToString(), p1);
|
|
_TPrices3.SetPrice(item.id.ToString(), p2);
|
|
_TPrices4.SetPrice(item.id.ToString(), p3);
|
|
_TPrices5.SetPrice(item.id.ToString(), p4);
|
|
_TPrices6.SetPrice(item.id.ToString(), p5);
|
|
_TPrices7.SetPrice(item.id.ToString(), p6);
|
|
_TPrices8.SetPrice(item.id.ToString(), p7);
|
|
_TPrices9.SetPrice(item.id.ToString(), p8);
|
|
_TPrices10.SetPrice(item.id.ToString(), p9);
|
|
_TPrices11.SetPrice(item.id.ToString(), p10);
|
|
_TPrices12.SetPrice(item.id.ToString(), p11);
|
|
_TPrices13.SetPrice(item.id.ToString(), p12);
|
|
_TPrices14.SetPrice(item.id.ToString(), upPrice);
|
|
}
|
|
|
|
TPrices1 = _TPrices1;
|
|
TPrices2 = _TPrices2;
|
|
TPrices3 = _TPrices3;
|
|
TPrices4 = _TPrices4;
|
|
TPrices5 = _TPrices5;
|
|
TPrices6 = _TPrices6;
|
|
TPrices7 = _TPrices7;
|
|
TPrices8 = _TPrices8;
|
|
TPrices9 = _TPrices9;
|
|
TPrices10 = _TPrices10;
|
|
TPrices11 = _TPrices11;
|
|
TPrices12 = _TPrices12;
|
|
TPrices13 = _TPrices13;
|
|
TPrices14 = _TPrices14;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取标的现价
|
|
/// </summary>
|
|
/// <param name="underlyingCode"></param>
|
|
/// <param name="CurUser"></param>
|
|
/// <param name="tradeDate"></param>
|
|
/// <returns></returns>
|
|
public static double GetUnderlyingPrice(string underlyingCode, OptUserInfo CurUser, DateTime? tradeDate = null)
|
|
{
|
|
double price = 0;
|
|
|
|
var udm = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode);
|
|
|
|
SyntheticPriceModel synthetic = null;
|
|
|
|
if (udm != null)
|
|
{
|
|
if (udm.CommodityCode == "组合标的")
|
|
{
|
|
synthetic = new SyntheticUnderlyingPriceService(CurUser).GetPriceModel(underlyingCode);
|
|
price = synthetic.Price;
|
|
}
|
|
else
|
|
{
|
|
price = udm.Price ?? 0;
|
|
}
|
|
if (tradeDate != null && tradeDate != valuedateBLL.ValueDate)
|
|
{
|
|
if (EodPriceQueryService.TryGetEodPrice(Convert.ToDateTime(tradeDate), underlyingCode, out var eodPrice))
|
|
{
|
|
price = eodPrice.ClosePrice;
|
|
}
|
|
}
|
|
}
|
|
|
|
return price;
|
|
}
|
|
|
|
|
|
|
|
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 clientGroups = req.tradeSpans.GroupBy(t => t.ClientId);
|
|
|
|
foreach (var clientGroup in clientGroups)
|
|
{
|
|
var underlyingGroup = clientGroup.GroupBy(t => t.UnderlyingId).Select(t => new ClientSpan
|
|
{
|
|
UnderlyingId = t.Key,
|
|
ClientId = clientGroup.Key ?? 0,
|
|
ValueDate = req.settleDate,
|
|
Spv1 = -t.Sum(g => g.Spv1),
|
|
Spv2 = -t.Sum(g => g.Spv2),
|
|
Spv3 = -t.Sum(g => g.Spv3),
|
|
Spv4 = -t.Sum(g => g.Spv4),
|
|
Spv5 = -t.Sum(g => g.Spv5),
|
|
Spv6 = -t.Sum(g => g.Spv6),
|
|
Spv7 = -t.Sum(g => g.Spv7),
|
|
Spv8 = -t.Sum(g => g.Spv8),
|
|
Spv9 = -t.Sum(g => g.Spv9),
|
|
Spv10 = -t.Sum(g => g.Spv10),
|
|
Spv11 = -t.Sum(g => g.Spv11),
|
|
Spv12 = -t.Sum(g => g.Spv12),
|
|
Spv13 = -t.Sum(g => g.Spv13),
|
|
Spv14 = -t.Sum(g => g.Spv14),
|
|
OptId = req.userId,
|
|
OptName = req.userName,
|
|
OptDate = DateTime.Now,
|
|
SpanType = req.SpanType,
|
|
}).ToList();
|
|
|
|
foreach (var item in underlyingGroup)
|
|
{
|
|
item.SetWorstCastClientPayableMin();
|
|
item.WorstCastClientPayable = Math.Min((double)item.WorstCastClientPayable, 0);
|
|
|
|
#region 更新tradeSpan,使得每笔交易的持仓预付金和客户预付金计算用的Spv组保持一致
|
|
|
|
var tradeIdList = clientGroup.Select(x => x.TradeId);
|
|
var tradeSpansUpdate = db.trade_span.Where(x => tradeIdList.Contains(x.TradeId) && x.ClientId == item.ClientId && x.UnderlyingId == item.UnderlyingId && x.ValueDate == req.settleDate).ToList();
|
|
var tradeSpansReq = req.tradeSpans.Where(x => tradeIdList.Contains(x.TradeId) && 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);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv1);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv2)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv2);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv2);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv3)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv3);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv3);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv4)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv4);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv4);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv5)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv5);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv5);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv6)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv6);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv6);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv7)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv7);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv7);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv8)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv8);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv8);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv9)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv9);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv9);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv10)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv10);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv10);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv11)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv11);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv11);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv12)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv12);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv12);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv13)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv13);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv13);
|
|
}
|
|
else if (item.WorstCastClientPayable == item.Spv14)
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = x.Spv14);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = x.Spv14);
|
|
}
|
|
else
|
|
{
|
|
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = 0);
|
|
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = 0);
|
|
}
|
|
#endregion
|
|
}
|
|
var clientSpan = new ClientSpan
|
|
{
|
|
ClientId = clientGroup.Key ?? 0,
|
|
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),
|
|
Spv8 = underlyingGroup.Sum(g => g.Spv8),
|
|
Spv9 = underlyingGroup.Sum(g => g.Spv9),
|
|
Spv10 = underlyingGroup.Sum(g => g.Spv10),
|
|
Spv11 = underlyingGroup.Sum(g => g.Spv11),
|
|
Spv12 = underlyingGroup.Sum(g => g.Spv12),
|
|
Spv13 = underlyingGroup.Sum(g => g.Spv13),
|
|
Spv14 = underlyingGroup.Sum(g => g.Spv14),
|
|
//负数代表客户应缴预付金,正数代表客户应收预付金
|
|
WorstCastClientPayable = underlyingGroup.Sum(g => g.WorstCastClientPayable),
|
|
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
|
|
};
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 获取初始预付金率
|
|
/// </summary>
|
|
/// <param name="trade"></param>
|
|
/// <returns></returns>
|
|
public double? GetInitialMarginRatio(trade trade)
|
|
{
|
|
if (trade == null)
|
|
{
|
|
return 0;
|
|
}
|
|
if (!trade.VarietyId.HasValue || trade.VarietyId <= 0)
|
|
{
|
|
return 0;
|
|
}
|
|
if (trade.StockEqvNotional == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
var variety = DataCacheManager.GetVarietyDataSource().GetData(trade.VarietyId ?? 0);
|
|
if (variety == null)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//OTC-8856 Start
|
|
var UpLimitValue = variety.UpLimitValue;
|
|
//var UpLimitValue =((Math.Abs(trade.Underlying.UpDownLimitValue) > 1e-5) ? trade.Underlying.UpDownLimitValue : variety.UpLimitValue);
|
|
//End
|
|
|
|
if (trade.StockEqvNotional <= 5000000)
|
|
{
|
|
return 2 * UpLimitValue;
|
|
}
|
|
else if (trade.StockEqvNotional <= 10000000)
|
|
{
|
|
return 2.5 * UpLimitValue;
|
|
}
|
|
else if (trade.StockEqvNotional <= 20000000)
|
|
{
|
|
return 3 * UpLimitValue;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取维持预付金率
|
|
/// </summary>
|
|
/// <param name="trade"></param>
|
|
/// <returns></returns>
|
|
public double? GetPositionMarginRatio(trade trade)
|
|
{
|
|
if (trade == null)
|
|
{
|
|
return 0;
|
|
}
|
|
if (!trade.VarietyId.HasValue || trade.VarietyId <= 0)
|
|
{
|
|
return 0;
|
|
}
|
|
if (trade.StockEqvNotional == 0)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
//underlying_manager
|
|
|
|
|
|
var variety = DataCacheManager.GetVarietyDataSource().GetData(trade.VarietyId ?? 0);
|
|
if (variety == null)
|
|
{
|
|
return 0;
|
|
}
|
|
if (trade.StockEqvNotional <= 5000000)
|
|
{
|
|
return 1.5 * variety.UpLimitValue;
|
|
}
|
|
else if (trade.StockEqvNotional <= 10000000)
|
|
{
|
|
return 2 * variety.UpLimitValue;
|
|
}
|
|
else if (trade.StockEqvNotional <= 20000000)
|
|
{
|
|
return 2.5 * variety.UpLimitValue;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取初始预付金
|
|
/// </summary>
|
|
/// <param name="trade"></param>
|
|
/// <returns></returns>
|
|
//public double GetInitialMargin(trade trade)
|
|
//{
|
|
// return DoInitialMarginCalculationV2(trade);
|
|
//}
|
|
|
|
//public double DoInitialMarginCalculationV2(trade trade)
|
|
//{
|
|
// if (trade.BuySell == "卖出")
|
|
// {
|
|
// return 0;
|
|
// }
|
|
|
|
// var underlying = DataCacheManager.GetUnderlyingDataSource().GetData(trade.UnderlyingId);
|
|
// underlying.QuotationDate = trade.TradeDate;
|
|
|
|
// var spotPrices = new double[] { trade.SpotPrice ?? 0 };
|
|
|
|
// string userGroup = UserBLL.GetUserGroup(trade.TraderId ?? 0);
|
|
// var volSurfaceData = VolatilityHelper.GetVol(underlying.QuotationDate.Value, "交易", underlying.UnderlyingCode, userGroup);
|
|
|
|
// var vol = OptionCalculator.GetInterpolatedVol(
|
|
// VolConstructionType.Normal,
|
|
// trade.OptId.ToString(),
|
|
// volSurfaceData,
|
|
// underlying.QuotationDate?.ToString("yyyy-MM-dd"),
|
|
// underlying.UnderlyingCode,
|
|
// trade.ExerciseDate?.ToString("yyyy-MM-dd"),
|
|
// trade.Strike ?? 0.0,
|
|
// isBuy: true,
|
|
// isCall: trade.CallPut == "Call",
|
|
// spotPrice: spotPrices[0],
|
|
// isMoneynessOption: trade.IsMoneynessOptionData,
|
|
// timeToMaturityDays: trade.TTMDays ?? double.NaN);
|
|
|
|
// if (!trade.NoRiskRate.HasValue)
|
|
// {
|
|
// trade.NoRiskRate = (valuedateBLL.SystemDate.RiskFreeRate ?? 0) * 0.01;
|
|
// }
|
|
|
|
// string fixing = null;
|
|
// //亚式期权
|
|
// if (trade.TradeType == "亚式期权" || trade.StructureType == "亚式熊市价差")
|
|
// {
|
|
// fixing = TradeCalcHelper.GetFixingStringForAsianOption(trade, trade.TradeDate);
|
|
// }
|
|
// var optionValue = ValueCalculator.GetOptionValueResultV2(
|
|
// trade.OptId.ToString(),
|
|
// underlying,
|
|
// trade,
|
|
// new double[] { vol },
|
|
// spotPrices,
|
|
// fixing,
|
|
// preciseTimeMode: true);
|
|
// //预付金初始价值=期初期权价值+CashDelta(t)*预付金初始比例(预付金初始比例)
|
|
// return (trade.TradePrice ?? 0) + ((optionValue == null) ? 0 : Math.Abs(optionValue.DeltaCash)) * (trade.InitialMarginRatio ?? 0);
|
|
//}
|
|
|
|
public override double GetTradeMargin(GetTradeMarginReq req)
|
|
{
|
|
var tradeMargin = RunMarginCalculation(req.GetRunMarginCalculationReq());
|
|
if (null != tradeMargin)
|
|
{
|
|
return tradeMargin.FirstOrDefault()?.WorstCastClientPayable ?? 0.0;
|
|
}
|
|
return 0.0;
|
|
}
|
|
}
|
|
}
|