551 lines
27 KiB
C#
551 lines
27 KiB
C#
using YLErp.BLL.Calculation;
|
||
using YLErp.BLL.Eod;
|
||
using YLErp.DBModels.Helpers;
|
||
using YLErp.Enums;
|
||
using YLErp.Helpers;
|
||
using YLErp.QdpModule;
|
||
|
||
namespace YLErp.BLL.MarginCalculation
|
||
{
|
||
/// <summary>
|
||
/// 渤海荣盛
|
||
/// </summary>
|
||
public class BHRSMarginCalculation : MarginCalculationBase
|
||
{
|
||
// 定义一个静态变量来保存类的实例
|
||
public static readonly BHRSMarginCalculation Instance;
|
||
|
||
static BHRSMarginCalculation()
|
||
{
|
||
Instance = new BHRSMarginCalculation();
|
||
}
|
||
|
||
// 定义私有构造函数,使外界不能创建该类实例
|
||
private BHRSMarginCalculation()
|
||
{
|
||
}
|
||
|
||
public override List<trade_span> RunMarginCalculation(RunMarginCalculationReq req)
|
||
{
|
||
var tradeSpans = new List<trade_span>();
|
||
|
||
if (req?.tradeList == null || !req.tradeList.Any())
|
||
{
|
||
return tradeSpans;
|
||
}
|
||
|
||
var helper = new RunMarginCalculationHelper(req, _underlyingDataProvider);
|
||
|
||
var tempStockTradeList = req.tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.Stock).ToList();
|
||
if (tempStockTradeList.Any())
|
||
{
|
||
var stockTradeSpanlist = StockMarginCalculation(req.Clone(tempStockTradeList), helper);
|
||
if (stockTradeSpanlist.Count > 0)
|
||
{
|
||
tradeSpans.AddRange(stockTradeSpanlist);
|
||
}
|
||
}
|
||
|
||
var tempFutureTradeList = req.tradeList.Where(t => t.UnderlyingInstrumentType == ConsGlobal.InstrumentType.CommodityFutures).ToList();
|
||
if (tempFutureTradeList.Any())
|
||
{
|
||
|
||
var tradeList = tempFutureTradeList.Where(a => a.TradeType != "远期").ToList();
|
||
if (tradeList.Any())
|
||
{
|
||
req = req.Clone(tradeList);
|
||
var futureTradeSpanlist = FutureMarginCalculation(req, helper);
|
||
if (futureTradeSpanlist.Count > 0)
|
||
{
|
||
tradeSpans.AddRange(futureTradeSpanlist);
|
||
}
|
||
}
|
||
|
||
var forwardTradeList = tempFutureTradeList.Where(a => a.TradeType == "远期").ToList();
|
||
if (forwardTradeList.Any())
|
||
{
|
||
req = req.Clone(forwardTradeList);
|
||
var futureTradeSpanlist = ForwardMarginCalculation(req, helper);
|
||
if (futureTradeSpanlist.Count > 0)
|
||
{
|
||
tradeSpans.AddRange(futureTradeSpanlist);
|
||
}
|
||
}
|
||
}
|
||
return tradeSpans;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 股票类期权计算预付金
|
||
/// </summary>
|
||
private List<trade_span> StockMarginCalculation(RunMarginCalculationReq req, RunMarginCalculationHelper helper)
|
||
{
|
||
var tradeSpans = new List<trade_span>();
|
||
|
||
if (req?.tradeList == null || !req.tradeList.Any())
|
||
{
|
||
return tradeSpans;
|
||
}
|
||
|
||
var marginRation = valuedateBLL.SystemDate.MarginRatio ?? 0.15;
|
||
|
||
foreach (var t in req.tradeList)
|
||
{
|
||
var client = helper.GetClient(t.ClientId);
|
||
|
||
if (client == null)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
double twoSideMargin;
|
||
|
||
if (helper.GetSpecialMargin(t, 0, out var value))
|
||
{
|
||
twoSideMargin = value;
|
||
}
|
||
else
|
||
{
|
||
var clientRatio = client?.Ratio ?? 1.0;
|
||
//如果是股票去名义本金,如果是期货取:份额 * 即期价格
|
||
var baseValue = (t.StockEqvNotional == 0 ? TradeHelper.GetStockEqvNotional(t.Notional * t.SpotPrice, t.ParticipationRate, t.AnnualizeFactor) : t.StockEqvNotional) * marginRation;
|
||
value = baseValue * (t.BuySell == "买入" ? 1 : (PS.Config.ErpElement.TwoSideMargin && client.MarginOptionType == 1 ? -1 : 0)) * clientRatio;
|
||
twoSideMargin = baseValue * (t.BuySell == "买入" ? 1 : -1) * clientRatio;
|
||
}
|
||
|
||
tradeSpans.Add(new trade_span
|
||
{
|
||
TradeId = t.id,
|
||
OptDate = DateTime.Now,
|
||
OptId = req.userId,
|
||
OptName = req.userName,
|
||
ClientId = client.ClientId,
|
||
UnderlyingId = t.UnderlyingId,
|
||
UnderlyingCode = t.UnderlyingCode,
|
||
ValueDate = req.settleDate,
|
||
Spv1 = value,
|
||
Spv2 = value,
|
||
Spv3 = value,
|
||
Spv4 = value,
|
||
WorstCastClientPayable = value,
|
||
TwoSideMargin = twoSideMargin
|
||
});
|
||
}
|
||
|
||
return tradeSpans;
|
||
}
|
||
/// <summary>
|
||
/// 商品期权计算预付金
|
||
/// </summary>
|
||
private List<trade_span> FutureMarginCalculation(RunMarginCalculationReq req, RunMarginCalculationHelper helper)
|
||
{
|
||
var futureTradeList = req.tradeList;
|
||
var tradeSpans = new List<trade_span>();
|
||
using (var db = new YLContext())
|
||
{
|
||
if (!req.hasOptionInfo)
|
||
{
|
||
tradeBLL.SetFieldsByTradeType(futureTradeList);
|
||
}
|
||
var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(
|
||
valueDate: req.settleDate,
|
||
tradeList: futureTradeList,
|
||
calcScenario: req.GetCalcScenario(),
|
||
priceProvider: req.PriceProvider,
|
||
pricingRequest: QdpPricingRequest.BASIC_GREEKS, addVolRateDic: null,
|
||
volType: req.volType,
|
||
settlementType: req.settlementType,
|
||
isUseTradeVol: PS.Config.IsTradeVol,
|
||
preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin);
|
||
|
||
logger.Info($"商品期货预付金计算,交易入:[{futureTradeList.Count}条],返回[{tradeRiskResult.Results.Count}],错误:{tradeRiskResult.ErrorMessage}");
|
||
|
||
//计算预付金包含错误信息时弹出错误信息
|
||
if (!string.IsNullOrWhiteSpace(tradeRiskResult.ErrorMessage))
|
||
{
|
||
throw new Exception(tradeRiskResult.ErrorMessage);
|
||
}
|
||
|
||
if (tradeRiskResult.Results.Count < 1)
|
||
{
|
||
return tradeSpans;
|
||
}
|
||
|
||
var vegaCoefficient = valuedateBLL.SystemDate.FutureMarginVegaCoefficient ?? 3;
|
||
var omegaCoefficient = valuedateBLL.SystemDate.FutureMarginOmegaCoefficient ?? 2.5;
|
||
var alphaRate = valuedateBLL.SystemDate.FutureMarginAlphaRate ?? 1;
|
||
|
||
foreach (var item in tradeRiskResult.Results)
|
||
{
|
||
var tempVariety = _underlyingDataProvider.GetVariety(item.Trade.UnderlyingCode);
|
||
double closePrice = 0.0;
|
||
switch (req.CalcMarginType)
|
||
{
|
||
case CalcMarginTypeEnum.None:
|
||
case CalcMarginTypeEnum.EodMargin:
|
||
closePrice = req.PriceProvider.GetPrice(item.Trade.UnderlyingCode);
|
||
break;
|
||
case CalcMarginTypeEnum.InitialMargin:
|
||
closePrice = item.Trade.SpotPrice ?? 0;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
var client = helper.GetClient(item.Trade.ClientId);
|
||
if (item.ValueResult == null)
|
||
{
|
||
throw new Exception("PV结算结果为null");
|
||
}
|
||
|
||
var deltaMerge = item.ValueResult.Delta;
|
||
var vegaMerge = item.ValueResult.Vega;
|
||
var gammaMerge = item.ValueResult.Gamma;
|
||
var pvMerge = item.ValueResult.Pv;
|
||
|
||
var PositionPnl = req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? 0 :
|
||
pvMerge - (EodOperationBase.GetPositionCost(item.Trade.TradePrice ?? 0, item.Trade.Notional, item.Trade.OriginalNotional ?? 0, item.Trade.BuySell));
|
||
|
||
PositionPnl = PositionPnl > 0 ? PositionPnl : 0;
|
||
|
||
bool isTwoSide = HasTwoSideMargin(item.Trade.ClientId);
|
||
//逐笔预付金算法
|
||
var margin = MarginAlgorithm(deltaMerge, pvMerge, closePrice, isTwoSide, tempVariety.Margin ?? 0, item.Trade, PositionPnl);
|
||
|
||
if (item.Trade.TradeType == "自定义交易")
|
||
{
|
||
if (helper.GetSpecialMargin(item.Trade, 0, out var value))
|
||
{
|
||
margin = value;
|
||
}
|
||
}
|
||
|
||
tradeSpans.Add(new trade_span
|
||
{
|
||
TradeId = item.Trade.id,//默认记录为第一条交易记录中
|
||
OptDate = DateTime.Now,
|
||
OptId = req.userId,
|
||
OptName = req.userName,
|
||
ClientId = item.Trade.ClientId,
|
||
ValueDate = req.settleDate,
|
||
UnderlyingId = item.Trade.UnderlyingId,
|
||
UnderlyingCode = item.Trade.UnderlyingCode,
|
||
DeltaMargin = margin,
|
||
WorstCastClientPayable = margin,
|
||
Comment = $"delta:{deltaMerge},closePrice:{closePrice},pv:{pvMerge}" +
|
||
$",gamma{gammaMerge},交易员方向:{item.Trade.BuySell},持仓盈亏:{PositionPnl},预付金率:{tempVariety.Margin},单双向:{client.MarginOptionType}"
|
||
});
|
||
|
||
}
|
||
return tradeSpans;
|
||
}
|
||
}
|
||
|
||
private List<trade_span> ForwardMarginCalculation(RunMarginCalculationReq req, RunMarginCalculationHelper helper)
|
||
{
|
||
var futureTradeList = req.tradeList;
|
||
var tradeSpans = new List<trade_span>();
|
||
using (var db = new YLContext())
|
||
{
|
||
if (!req.hasOptionInfo)
|
||
{
|
||
tradeBLL.SetFieldsByTradeType(futureTradeList);
|
||
}
|
||
var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(
|
||
valueDate: req.settleDate,
|
||
tradeList: futureTradeList,
|
||
calcScenario: req.GetCalcScenario(),
|
||
priceProvider: req.PriceProvider,
|
||
pricingRequest: QdpPricingRequest.BASIC_GREEKS, addVolRateDic: null,
|
||
volType: req.volType, isUseTradeVol: PS.Config.IsTradeVol,
|
||
preciseTimeMode: req.CalcMarginType != CalcMarginTypeEnum.EodMargin);
|
||
|
||
logger.Info($"远期预付金计算,交易入:[{futureTradeList.Count}条],返回[{tradeRiskResult.Results.Count}],错误:{tradeRiskResult.ErrorMessage}");
|
||
|
||
//计算预付金包含错误信息时弹出错误信息
|
||
if (!string.IsNullOrWhiteSpace(tradeRiskResult.ErrorMessage))
|
||
{
|
||
throw new Exception(tradeRiskResult.ErrorMessage);
|
||
}
|
||
|
||
if (tradeRiskResult.Results.Count < 1)
|
||
{
|
||
return tradeSpans;
|
||
}
|
||
var vegaCoefficient = valuedateBLL.SystemDate.FutureMarginVegaCoefficient ?? 3;
|
||
var omegaCoefficient = valuedateBLL.SystemDate.FutureMarginOmegaCoefficient ?? 2.5;
|
||
var alphaRate = valuedateBLL.SystemDate.FutureMarginAlphaRate ?? 1;
|
||
//如果持仓中的所有远期delta方向相同,那么无视delta方向,每笔远期交易都按照delta绝对值计算margin;
|
||
bool IsDeltaMerge = tradeRiskResult.Results.All(a => a.ValueResult.Delta >= 0) || tradeRiskResult.Results.All(a => a.ValueResult.Delta <= 0);
|
||
|
||
var tradeIds = futureTradeList.Where(O => O.id > 0).Select(O => O.id);
|
||
var tradeCashDict =
|
||
db.trade_cash.Where(O => tradeIds.Contains(O.TradeId) && O.ValidState != "InValid" && !O.IsDeleted && O.Action != ClientCashInCashOut.系统操作_期权费)
|
||
.AsEnumerable()
|
||
.GroupBy(O => O.TradeId)
|
||
.ToDictionary(K => K.Key, V => V.ToList());
|
||
|
||
var marginCostDict = db.eod_forward_margin.Where(x => x.ValueDate == req.settleDate && tradeIds.Contains(x.TradeId))
|
||
.AsEnumerable()
|
||
.GroupBy(O => O.TradeId)
|
||
.ToDictionary(K => K.Key, V => V.FirstOrDefault()?.MarginCost ?? 0);
|
||
|
||
foreach (var item in tradeRiskResult.Results)
|
||
{
|
||
var tempVariety = _underlyingDataProvider.GetVariety(item.Trade.UnderlyingCode);
|
||
double closePrice = 0.0;
|
||
switch (req.CalcMarginType)
|
||
{
|
||
case CalcMarginTypeEnum.None:
|
||
case CalcMarginTypeEnum.EodMargin:
|
||
closePrice = req.PriceProvider.GetPrice(item.Trade.UnderlyingCode);
|
||
break;
|
||
case CalcMarginTypeEnum.InitialMargin:
|
||
closePrice = item.Trade.SpotPrice ?? 0;
|
||
break;
|
||
default:
|
||
break;
|
||
}
|
||
|
||
if (item.ValueResult == null)
|
||
{
|
||
throw new Exception("PV结算结果为null");
|
||
}
|
||
|
||
var deltaMerge = item.ValueResult.Delta;
|
||
var vegaMerge = item.ValueResult.Vega;
|
||
var gammaMerge = item.ValueResult.Gamma;
|
||
var pvMerge = item.ValueResult.Pv;
|
||
var marginCost = marginCostDict.TryGetValue(item.Trade.id, out var margincost) ? margincost : 0;
|
||
var unwindTradeCashList = tradeCashDict.TryGetValue(item.Trade.id, out var cashList) ? cashList : new List<trade_cash>();
|
||
//平仓比例
|
||
double unwindRatio = unwindTradeCashList.Any() ? unwindTradeCashList.Sum(a => a.UnwindNotional.Value) / item.Trade.OriginalNotional.Value : 0;
|
||
//持仓比例
|
||
double positionRatio = 1 - unwindRatio;
|
||
//持仓盈亏 = 持仓市值+开仓总费用 * 持仓比例
|
||
var pnl = pvMerge + item.Trade.TradePrice.Value * positionRatio + marginCost;
|
||
logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber}持仓盈亏 = 持仓市值 + 开仓总费用 * 持仓比例");
|
||
logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber}PnL = {pvMerge} + {item.Trade.TradePrice.Value} * {positionRatio} + {marginCost}");
|
||
pnl = req.CalcMarginType == CalcMarginTypeEnum.InitialMargin ? 0 : Math.Max(0, pnl);
|
||
|
||
deltaMerge = IsDeltaMerge ? Math.Abs(deltaMerge) : deltaMerge;
|
||
//预付金计算公式: delta * 标的收盘价 * 交易所预付金率 + 客户亏损部分
|
||
double value = deltaMerge * closePrice * (tempVariety.Margin ?? 0) + pnl;
|
||
logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber}预付金计算公式: delta * 标的收盘价 * 交易所预付金率 + 客户亏损部分");
|
||
logger.Info($"远期预付金计算,交易:{item.Trade.TradeNumber}预付金 = {deltaMerge} * {closePrice} * {(tempVariety.Margin ?? 0)} + {pnl}");
|
||
|
||
tradeSpans.Add(new trade_span
|
||
{
|
||
TradeId = item.Trade.id,//默认记录为第一条交易记录中
|
||
OptDate = DateTime.Now,
|
||
OptId = req.userId,
|
||
OptName = req.userName,
|
||
ClientId = item.Trade.ClientId,
|
||
ValueDate = req.settleDate,
|
||
UnderlyingId = item.Trade.UnderlyingId,
|
||
UnderlyingCode = item.Trade.UnderlyingCode,
|
||
DeltaMargin = value,
|
||
WorstCastClientPayable = value,
|
||
Comment = $"远期交易,delta:{deltaMerge},closePrice:{closePrice},pv:{pvMerge}" +
|
||
$",gamma{gammaMerge},交易员方向:{item.Trade.BuySell},预付金率:{tempVariety.Margin}"
|
||
});
|
||
}
|
||
|
||
}
|
||
return 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;
|
||
}
|
||
|
||
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.AsEnumerable().GroupBy(t => t.ClientId);
|
||
|
||
foreach (var clientGroup in clientGroups)
|
||
{
|
||
|
||
List<ClientSpan> clientSpans = new List<ClientSpan>();
|
||
|
||
var tradeSpanGroup = clientGroup.ToList();
|
||
var tradeIds = tradeSpanGroup.Select(a => a.TradeId).ToList();
|
||
|
||
var notForwardTrades = db.trade.Where(a => tradeIds.Contains(a.id) && a.TradeType != "远期").ToList();
|
||
|
||
#region 非远期
|
||
if (notForwardTrades.Any())
|
||
{
|
||
var notForwardTradeIds = notForwardTrades.Select(a => a.id);
|
||
//双向追保,客户只有买入交易 则预付金为0
|
||
if (notForwardTrades.All(a => a.BuySell == "卖出") && HasTwoSideMargin(clientGroup.Key ?? 0))
|
||
{
|
||
|
||
var tradeSpansUpdate = db.trade_span.Where(x => notForwardTradeIds.Contains(x.TradeId) && x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate).ToList();
|
||
var tradeSpansReq = req.tradeSpans.Where(x => notForwardTradeIds.Contains(x.TradeId) && x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate).ToList();
|
||
tradeSpansUpdate.ForEach(x => x.WorstCastClientPayable = 0);
|
||
tradeSpansReq.ForEach(x => x.WorstCastClientPayable = 0);
|
||
|
||
var clientSpan = new ClientSpan
|
||
{
|
||
ClientId = clientGroup.Key ?? 0,
|
||
ValueDate = req.settleDate,
|
||
DeltaMargin = 0,
|
||
WorstCastClientPayable = 0
|
||
};
|
||
clientSpans.Add(clientSpan);
|
||
}
|
||
else
|
||
{
|
||
var umTradeSpanGroup = tradeSpanGroup.Where(x => notForwardTradeIds.Contains(x.TradeId) && x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate).AsEnumerable().GroupBy(a => a.UnderlyingId);
|
||
var umClientSpans = new List<ClientSpan>();
|
||
|
||
foreach (var umTrade in umTradeSpanGroup)
|
||
{
|
||
var umClientSpan = new ClientSpan
|
||
{
|
||
UnderlyingId = umTrade.Key,
|
||
ClientId = clientGroup.Key ?? 0,
|
||
ValueDate = req.settleDate,
|
||
DeltaMargin = umTrade.Sum(u => u.DeltaMargin) * (-1)
|
||
};
|
||
|
||
umClientSpans.Add(umClientSpan);
|
||
}
|
||
var notForwardClientSpan = new ClientSpan
|
||
{
|
||
ClientId = clientGroup.Key ?? 0,
|
||
ValueDate = req.settleDate,
|
||
//负数代表客户应缴预付金,正数代表客户应收预付金
|
||
DeltaMargin = umClientSpans.Sum(g => g.DeltaMargin),
|
||
WorstCastClientPayable = umClientSpans.Sum(g => g.DeltaMargin)
|
||
};
|
||
clientSpans.Add(notForwardClientSpan);
|
||
}
|
||
}
|
||
#endregion
|
||
#region 远期
|
||
var forwardTrades = db.trade.Where(a => tradeIds.Contains(a.id) && a.TradeType == "远期").ToList();
|
||
if (forwardTrades.Any())
|
||
{
|
||
var forwardTradeIds = forwardTrades.Select(a => a.id);
|
||
var forwardTradeSpans = tradeSpanGroup.Where(x => forwardTradeIds.Contains(x.TradeId) && x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate);
|
||
|
||
var margin = Math.Abs((forwardTradeSpans.Sum(g => g.DeltaMargin) ?? 0)) * -1;
|
||
var forwardClientSpan = new ClientSpan
|
||
{
|
||
ClientId = clientGroup.Key ?? 0,
|
||
ValueDate = req.settleDate,
|
||
//负数代表客户应缴预付金,正数代表客户应收预付金
|
||
DeltaMargin = margin,
|
||
WorstCastClientPayable = margin
|
||
};
|
||
clientSpans.Add(forwardClientSpan);
|
||
|
||
var tradeSpansUpdate = db.trade_span.Where(x => forwardTradeIds.Contains(x.TradeId) && x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate).ToList();
|
||
var tradeSpansReq = req.tradeSpans.Where(x => forwardTradeIds.Contains(x.TradeId) && x.ClientId == clientGroup.Key && x.ValueDate == req.settleDate).ToList();
|
||
if (margin > 0)
|
||
{
|
||
tradeSpansUpdate.ForEach(a => a.WorstCastClientPayable = 0);
|
||
tradeSpansReq.ForEach(a => a.WorstCastClientPayable = 0);
|
||
}
|
||
}
|
||
#endregion
|
||
|
||
var item = new ClientSpan
|
||
{
|
||
ClientId = clientGroup.Key ?? 0,
|
||
ValueDate = req.settleDate,
|
||
//负数代表客户应缴预付金,正数代表客户应收预付金
|
||
DeltaMargin = clientSpans.Sum(g => g.DeltaMargin),
|
||
WorstCastClientPayable = clientSpans.Sum(g => g.DeltaMargin),
|
||
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(item);
|
||
|
||
}
|
||
}
|
||
//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();
|
||
//筛选出可以修改的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.SaveChanges();
|
||
return req.tradeSpans;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 预付金算法
|
||
/// </summary>
|
||
/// <returns></returns>
|
||
public double? MarginAlgorithm(double deltaMerge, double pvMerge, double closePrice, bool isTwoSide, double Margin, trade tradeModel, double PositionPnl)
|
||
{
|
||
//交易员买入 delta为正,卖出为负
|
||
deltaMerge = tradeModel.BuySell == "买入" ? Math.Abs(deltaMerge) : -Math.Abs(deltaMerge);
|
||
var value = 0.0;
|
||
// 预付金 = delta(交易员方向delta) * 标的收盘价 * 交易所预付金率 + 持亏(交易员方向)
|
||
value = deltaMerge * closePrice * Margin + PositionPnl;
|
||
|
||
if (tradeModel.BuySell == "卖出" && !isTwoSide)//单向 客户买入
|
||
{
|
||
value = 0;
|
||
}
|
||
|
||
return value;
|
||
}
|
||
}
|
||
}
|