Files
zszq-trs/YLErpDAL/BLL/EodSettlement/RealtimePnlCalc.cs
T

2399 lines
140 KiB
C#

using CsvHelper;
using DocumentFormat.OpenXml.Bibliography;
using DocumentFormat.OpenXml.Drawing;
using DocumentFormat.OpenXml.Drawing.Charts;
using DocumentFormat.OpenXml.Spreadsheet;
using iTextSharp.text.pdf.security;
using NPOI.SS.Formula.Functions;
using Org.BouncyCastle.Asn1.Ocsp;
using Org.BouncyCastle.Math.EC.Multiplier;
using Qdp.Pricing.Base.Implementations;
using System.IO;
using System.Security.Cryptography.Xml;
using YLErp.Abstract;
using YLErp.Abstract.DataProviders;
using YLErp.BLL.Calculation;
using YLErp.BLL.MarginCalculation;
using YLErp.Cache;
using YLErp.Commons;
using YLErp.DataBase;
using YLErp.DBModels;
using YLErp.DBModels.Enums;
using YLErp.DBModels.Helpers;
using YLErp.Helpers;
using YLErp.Model;
using YLErp.Model.Enum;
using YLErp.Model.HengTaiModel;
using YLErp.Models;
using YLErp.Modules;
using YLErp.Modules.CalculationModule;
using YLErp.Modules.DataProviderModule;
using YLErp.Modules.EodModule;
using YLErp.Modules.EodModule.QueryModule;
using YLErp.Modules.SwapModule;
using YLErp.Modules.TradeDalModule;
using YLErp.QdpModule;
namespace YLErp.BLL.Eod
{
public class RealtimePnlCalc
{
public static bool IsListOld = true;
protected static object _RefrshLock = new object();
private static IYLCache _yLCache;
private static IKafkaProduce kafkaProduceHelper;
///系统参数
protected static valuedate _SystemDate = null;
///当前计算日期
protected static DateTime _ValueDate = DateTime.MinValue;
///最后交易日
protected static DateTime _LastSettleDate = DateTime.MinValue;
///最后结算日日终持仓信息
protected static List<eod_trade_position> _LastTradePositionList = new List<eod_trade_position>();
//
protected static List<trade> _TradeAllList;
protected static List<trade> _TradeSwapList;
protected static DateTime _TradeLastUpdateTime;
static IYcLogger _logger = LogFactory.GetLogger("RealtimePnlCalc");
/// 设置为false时 节假日当天
protected static bool IsFirstHoliday = true;
public static void InitCache(IYLCache yLCache)
{
_yLCache = yLCache;
}
public static void InitKafka(IKafkaProduce kafkaProduce)
{
kafkaProduceHelper = kafkaProduce;
}
/// <summary>
/// 刷新当日静态数据
/// </summary>
public static void RestInitData()
{
//刷新系统日期
valuedateBLL.ResetValueDate();
var isReload = false;
if (_ValueDate == DateTime.MinValue || _ValueDate != valuedateBLL.ValueDate)
{
isReload = true;
_SystemDate = valuedateBLL.SystemDate;
_ValueDate = _SystemDate.ValueDate;
}
InitLastTradePosition(isReload);
//增量初始化交易信息
InitTradeList();
}
/// <summary>
/// 初始化最后结算日结算信息
/// </summary>
private static void InitLastTradePosition(bool isReload)
{
if (isReload)
{
//获取昨日持仓
_LastSettleDate = EodOperationBase.GetLastSettlementDate(_ValueDate, true);
//获取昨日持仓
_LastTradePositionList = new EodSettlementService(OptUserInfo.SystemUser).GetEodTradePosition<eod_trade_position>(_LastSettleDate).ToList();
}
}
/// <summary>
/// 初始化交易信息
/// </summary>
private static void InitTradeList()
{
using (var db = new YLContext())
{
//获取停牌信息
var suspensionUnderlyingIdList = DataCacheProvider.GetUnderlyingDataSource().AsQueryable()
.Where(t => t.UnderlyingStatus == underlying_manager.Status_Suspension).Select(t => t.id).ToList();
//昨日持仓交易
var tradeIds = _LastTradePositionList.Where(t => 0 != t.TradeId).Select(t => t.TradeId).ToList();
//初始化待交易交易列表
_TradeAllList = db.trade.AsNoTracking().Where(t => t.ValidState != "InValid" && t.TradeDate <= _ValueDate && ConsTrade.NeedMarginTradeStatusList.Contains(t.TradeStatus)).ToList(); //有效的交易
//if (PS.Config.IsGuoJun)
//{
// _TradeAllList = _TradeAllList.Where(x=>x.TradeType!="收益互换").ToList();
//}
if (_TradeAllList != null && _TradeAllList.Any())
{
var allTradeIds = _TradeAllList.Select(d => d.id).Distinct().ToList();
var metaList = db.TradeMeta.AsNoTracking().Where(d => allTradeIds.Contains(d.TradeId)).ToList();
_TradeAllList.ForEach(p =>
{
p.MetaDic = metaList.Where(x => x.TradeId == p.id).ToDictionary(g => g.MetaKey, g => g.MetaValue);
});
}
_TradeSwapList = _TradeAllList.Where(x => x.TradeType == "收益互换").ToList();
_TradeAllList = _TradeAllList.Where(x => x.TradeType != "收益互换").ToList();
}
}
/// <summary>
/// 计算实时持仓并返回结果
/// </summary>
public static List<intraday_trade_position> RealtimePosition(OptUserInfo optUser)
{
if (optUser is null)
{
throw new ArgumentNullException(nameof(optUser));
}
lock (_RefrshLock)
{
using (var db = new YLContext())
{
RestInitData();
#region 获取昨日持仓 标的当前价格 当前持仓以及当日行权交易 并计算Risk信息
//标的
var underlyingPrice = DataCacheProvider.GetUnderlyingDataSource();
//获取待计算交列表
var tradeList = _TradeAllList;
var tradeIdList = tradeList.Select(t => t.id).ToList();
//设置option info
tradeBLL.SetFieldsByTradeType(tradeList);
//OTC 交易
var otcTradeList = tradeList.Where(t => !ConsTrade.TradeTypesForHedge.Contains(t.TradeType)).ToList();
new TradeDalService(optUser).SetSubTradeList(otcTradeList);
//OTC持仓交易
//过滤结构化交易,不参与计算预付金逻辑
var positionTradeList = otcTradeList.Where(t => ConsTrade.NeedMarginTradeStatusList.Contains(t.TradeStatus) && t.TradeType != "结构化交易").ToList();
//还未了结的交易
var liveTradeList = otcTradeList.Where(t => ConsTrade.LiveTradeStatusList.Contains(t.TradeStatus)).ToList();
//预付金计算
var req = new RunMarginCalculationReq(optUser)
{
tradeList = positionTradeList,
settleDate = _ValueDate,
PriceProvider = underlyingPrice,
hasOptionInfo = true
};
var tradeSpans = MarginDefault.RunMarginCalculation(req.Clone(forOtherSide: false));
//试算出交易买卖方向反向的tradeSpan(目前只有国君有这个需求,做过处理)
List<trade_span> tradeSpansOtherSide = new List<trade_span>();
if (MarginDefault.IsMarginCalcNeedSpecial(_ValueDate))
{
//试算出交易买卖方向反向的tradeSpan(目前只有国君有这个需求,做过处理)
tradeSpansOtherSide = MarginDefault.RunMarginCalculation(req.Clone(forOtherSide: true));
}
//根据交易预付金合计客户预付金计入client_span
var calcClientMarginReq = new CalcClientMarginReq(optUser)
{
settleDate = _ValueDate,
tradeSpans = tradeSpans,
tradeSpansOtherSide = tradeSpansOtherSide,
SpanType = ClientSpan.SpanType_RealTime
};
tradeSpans = MarginDefault.CalcClientMargin(calcClientMarginReq);
if (PS.Config.Company == Configuration.CompanyEnum.渤海)
{
//预付金计算
tradeSpans = MarginDefault.RunMarginCalculation(req.Clone(forOtherSide: false));
}
//实时计算rsik
var volTypes = new List<string> { "持仓" };
if (PS.Config.Is国投)
{
volTypes.Add("开仓");
}
var riskList = RealTimeRiskCalc(_ValueDate, liveTradeList, underlyingPrice, volTypes);
#endregion
#region 平仓费行权费 交易预付金计算 昨日持仓对冲交易过滤
var unWindTradeCashAction = new List<string> { ClientCashInCashOut.系统操作_平仓费, ClientCashInCashOut.系统操作_行权费, ClientCashInCashOut.系统操作_期权费 };
//获取平仓到期交易的trade_cash;
var tradeCashList = db.trade_cash.Where(t => tradeIdList.Contains(t.TradeId) && unWindTradeCashAction.Contains(t.Action) && t.ValidState != "InValid" && !t.IsDeleted).ToList();
//实时结果对象类
var realtimePositionList = new List<intraday_trade_position>();
//旧持仓对冲交易
var lastHedgingPositionList = _LastTradePositionList.Where(t => ConsTrade.TradeTypesForHedge.Contains(t.TradeType)).ToList();
#endregion
#region 处理昨日持仓今日为未交易股票 商品期货
//2021-02-02 实时持仓服务不再计算对冲交易,统一从 trade_Position 获取;
////对冲 交易
//var hedgeTradeList = db.ExchangeTrade.Where(t => t.IsValid && t.TradeDate <= _ValueDate && t.TradeDate > _LastSettleDate).ToList();
//var hedgePnlCalc = GetRealTimeHedgePnlCalc(_ValueDate, volType: "交易", optUser: optUser);
//var hedgePnl = hedgePnlCalc.Calculate(hedgeTradeList, lastHedgingPositionList);
//if (hedgePnl != null && hedgePnl.Any())
//{
// foreach (var t in hedgePnl)
// {
// var realtimePosition = new intraday_trade_position
// {
// ValueDate = _ValueDate,
// BookId = t.BookId,
// TradeType = t.TradeType,
// //ClientId = t.ClientId,
// PositionType = t.PositionType,
// UnderlyingCode = t.UnderlyingCode,
// BuySell = t.BuySell,
// Cost = Convert.ToDouble(t.Cost),
// Notional = Convert.ToDouble(t.Notional),
// Amount = Convert.ToDouble(t.Notional),
// LastPv = t.LastPv,
// Pv = t.Pv,
// DailyPnL = t.DailyPnL,
// TotalPnL = Convert.ToDouble(t.TotalPnl),
// PositionPnL = Convert.ToDouble(t.TotalPnl),
// ActualPv = Convert.ToDouble(t.Pv),
// ActualLastPv = Convert.ToDouble(t.LastPv),
// ActualDailyPnL = Convert.ToDouble(t.DailyPnL),
// ActualTotalPnL = Convert.ToDouble(t.TotalPnl),
// RealizedPnL = Convert.ToDouble(t.RealizedPnL),
// TradeStatus = "确认成交",
// OptDate = DateTime.Now,
// OptId = optUser.UserId,
// OptName = optUser.UserName,
// ParentTradeId = 0
// };
// realtimePositionList.Add(realtimePosition);
// }
//}
#endregion
#region 当日持仓期权交易 已行权已到期期权交易 以及当日对冲交易计算持仓
var tradeIds = otcTradeList.Select(x => x.id).ToArray();
var positionRealizedTradeCashs = db.trade_cash.Where(x => (x.Action == "系统操作-票息" || x.Action == "系统操作-互换") && x.ValidState != "InValid" && x.ValueDate <= _ValueDate && tradeIds.Contains(x.id) && !x.IsLastAction).ToList();
//循环交易 OTC交易
otcTradeList.ForEach(t =>
{
var Pv = 0.0; //当日pv
var RoundedPv = 0.0;
var LastPv = 0.0; //昨日pv
var Quantity = 0.0; //数量
var RealizedPnL = 0.0;//已归因盈亏
var DailyPnl = 0.0; //当日盈亏
var UnRealizedPnL = 0.0;//未归因盈亏
var TotalPnL = 0.0; //总盈亏
var PositionPnL = 0.0; //持仓盈亏
var RoundedPositionPnL = 0.0;
var NotionalPrincipal = 0.0;
var ActualPv = 0.0; //当日实际pv
var ActualLastPv = 0.0; //昨日实际pv
var ActualDailyPnl = 0.0; //当日实际浮动盈亏
var ActualTotalPnL = 0.0; //实际总盈亏
//部分平仓计算
var tempTradeCashList = tradeCashList.Where(a => a.TradeId == t.id);
//已实现
var RealizeProfitAndloss = tempTradeCashList.Any() ? tempTradeCashList.Sum(a => a.Amount) : 0.0;
//预付金
var tradeSpan = tradeSpans.FirstOrDefault(a => a.TradeId == t.id);
if (ConsTrade.LiveTradeStatusList.Contains(t.TradeStatus))
{
if (riskList.Any(a => a.TradeId == t.id))
{
var valueResult = riskList.FirstOrDefault(a => a.TradeId == t.id);
//最新pv
Pv = valueResult.Pv ?? 0;
RoundedPv = valueResult.RoundedPv ?? 0;
PositionPnL = valueResult.PositionPnl ?? 0.0;
RoundedPositionPnL = valueResult.RoundedPositionPnl ?? 0.0;
}
else
{
Pv = 0.0;
RoundedPv = 0.0;
}
//var valueResult = holdRisResult.ContainsKey(t.id) ? holdRisResult[t.id] : null;
//if (valueResult == null) continue;
var lastEodPosition = _LastTradePositionList.FirstOrDefault(e => e.TradeId == t.id);
//if (lastEodPosition != null) _LastTradePositionList.Remove(lastEodPosition);
//昨日pv
LastPv = lastEodPosition == null ? 0 : Convert.ToDouble(lastEodPosition.Pv);
//ActualLastPv = lastEodPosition == null ? 0 : Convert.ToDouble(lastEodPosition.ActualPv ?? 0.0);
//总持仓量
Quantity = lastEodPosition == null ? t.Notional : lastEodPosition.Amount;
//归因盈亏
RealizedPnL = lastEodPosition != null ? 0 : ((t.TradeSinglePrice ?? 0) * t.Notional * TradeCalcHelper.GetSign(t.BuySell) * (-1));
//未归因盈亏
UnRealizedPnL = Pv - LastPv;
//估值盈亏
DailyPnl = RealizedPnL + UnRealizedPnL;
//名义本金 如果是股票则取名义本金字段 如果为商品期货则去 spotprice * 份额
NotionalPrincipal = t.OriginalStockEqvNotional > 0
? ((t.OriginalStockEqvNotional * t.Notional / t.OriginalNotional) ?? 0) : TradeHelper.GetStockEqvNotional((t.SpotPrice ?? 0.0) * t.Notional, t.ParticipationRate, t.AnnualizeFactor);
//根据看涨看跌以及当前价格与行权价涨跌判断是否有实际pv
var callPutFlag = "Call".Equals(t.CallPut);
var unSpotPrice = underlyingPrice.GetPrice(t.UnderlyingCode);
var StrikeFlag = unSpotPrice > (t.IsMoneynessOptionData ? (t.Strike * t.SpotPrice) : (t.Strike ?? 0.0));
//实值pv计算
ActualPv = 0.0;
if (callPutFlag == StrikeFlag)
{
var Strike = t.IsMoneynessOptionData ? ((t.Strike ?? 0.0) * t.SpotPrice ?? 0.0) : t.Strike ?? 0.0;
var SpotPrice = (t.SpotPrice ?? 0);
if (SpotPrice > 0)
{
ActualPv = t.StockEqvNotional * Math.Max((unSpotPrice - Strike) * (callPutFlag ? 1 : -1), 0) / SpotPrice * TradeCalcHelper.GetSign(t.BuySell);
}
}
//实值浮动盈亏
//ActualDailyPnl = ActualPv - ActualLastPv;
//实值总盈亏
//ActualTotalPnL = (lastEodPosition == null ? 0 : lastEodPosition.ActualTotalPnL ?? 0.0) + ActualDailyPnl;
//总盈亏
TotalPnL = (lastEodPosition == null ? 0 : lastEodPosition.TotalPnL) + DailyPnl;
//PositionPnL = Pv + RealizeProfitAndloss;
}
else if (ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus))
{//已执行 已平仓 已到期的交易计算持仓信息
var tradeCash = tradeCashList.FirstOrDefault(a => a.TradeId == t.id && a.Action != ClientCashInCashOut.系统操作_期权费);
Pv = ActualPv = tradeCash == null ? 0.0 : tradeCash.Amount;
RoundedPv = Pv;
var lastEodPosition = _LastTradePositionList.FirstOrDefault(e => e.TradeId == t.id);
//if (lastEodPosition != null) _LastTradePositionList.Remove(lastEodPosition);
//昨日pv
LastPv = ActualLastPv = lastEodPosition == null ? 0 : Convert.ToDouble(lastEodPosition.Pv);
//总持仓量
Quantity = lastEodPosition == null ? t.Notional : lastEodPosition.Amount;
//归因盈亏
RealizedPnL = Pv;
//未归因盈亏
UnRealizedPnL = -LastPv;
//估值盈亏
DailyPnl = RealizedPnL + UnRealizedPnL;
//名义本金 如果是股票则取名义本金字段 如果为商品期货则去 spotprice * 份额
NotionalPrincipal = t.OriginalStockEqvNotional > 0
? ((t.OriginalStockEqvNotional * t.Notional / t.OriginalNotional) ?? 0) : TradeHelper.GetStockEqvNotional((t.SpotPrice ?? 0.0) * t.Notional, t.ParticipationRate, t.AnnualizeFactor);
//根据看涨看跌以及当前价格与行权价涨跌判断是否有实际pv
//实值pv计算
ActualDailyPnl = ActualPv - ActualLastPv;
//总盈亏
ActualTotalPnL = TotalPnL = Pv - ((t.TradeSinglePrice ?? 0.0) * t.Notional * TradeCalcHelper.GetSign(t.BuySell));
PositionPnL = RealizeProfitAndloss;
RoundedPositionPnL = RealizeProfitAndloss;
}
if (double.IsNaN(NotionalPrincipal))
{
NotionalPrincipal = 0;
}
var Margin = tradeSpan == null ? 0.0 : double.IsNaN(tradeSpan.WorstCastClientPayable ?? double.NaN) ? 0 : tradeSpan.WorstCastClientPayable.Value;
realtimePositionList.Add(
new intraday_trade_position
{
TradeId = t.id,
TradeNumber = t.TradeNumber,
ValueDate = _ValueDate,
BookId = t.AssetId,
TradeType = t.TradeType,
ClientId = t.ClientId,
UnderlyingCode = t.UnderlyingCode,
BuySell = t.BuySell,
Cost = (t.OriginalNotional > 0 ? t.TradePrice * t.Notional / t.OriginalNotional : t.TradePrice) ?? 0,
Notional = NotionalPrincipal,
Amount = Quantity,
LastPv = (decimal)LastPv,
Pv = (decimal)Pv,
RoundedPv = (decimal)RoundedPv,
DailyPnL = (decimal)DailyPnl,
RealizedPnL = RealizedPnL,
TotalPnL = TotalPnL,
PositionPnL = PositionPnL,
RoundedPositionPnl = RoundedPositionPnL,
ActualPv = ActualPv,
ActualLastPv = ActualLastPv,
ActualDailyPnL = ActualDailyPnl,
ActualTotalPnL = ActualTotalPnL,
Margin = Margin,
PositionRelizedAmount = positionRealizedTradeCashs.Where(x => x.TradeId == t.id).Sum(x => x.Amount),
TradeStatus = t.TradeStatus,
OptDate = DateTime.Now,
OptId = optUser.UserId,
OptName = optUser.UserName,
ParentTradeId = t.ParentTradeId,
//收益互换 应缴预付金 初始预付金 盈亏
SwapInitMargin = 0,
SwapWinLoss = 0,
SwapUnMargin = 0
});
});
#endregion
//删除过期和无效的交易
var intradayTradeIds = db.intraday_trade_position.Where(t => t.TradeId > 0).Select(t => t.TradeId).ToList();
var inValidTradeIds = db.trade.Where(t => intradayTradeIds.Contains(t.id) && t.ValidState == "InValid").Select(t => t.id).ToList();
var removePosition = db.intraday_trade_position.Where(t => t.ValueDate != _ValueDate || inValidTradeIds.Contains(t.TradeId));
if (removePosition.Any())
{
db.intraday_trade_position.RemoveRange(removePosition);
db.SaveChanges();
}
//插入数据库还未有过的数据(根据TradeId,ValueDate筛选)
var intradayTradeIdsExist = db.intraday_trade_position.Where(x => x.ValueDate == _ValueDate).Select(x => x.TradeId).ToList();
var realtimePositionListInsert = realtimePositionList.Where(x => !intradayTradeIdsExist.Contains(x.TradeId));
MySqlBulkExtensions.BulkInsert(db, realtimePositionListInsert);
//根据TradeId,ValueDate更新已经存在的数据
var tradeids = realtimePositionList.Select(t => t.TradeId).ToList();
var intradayTradePositions = db.intraday_trade_position.Where(x => tradeids.Contains(x.TradeId) && x.ValueDate == _ValueDate).ToList();
for (var i = 0; i < intradayTradePositions.Count; i++)
{
var intradayTradePosition = realtimePositionList.FirstOrDefault(x => x.TradeId == intradayTradePositions[i].TradeId)?.Clone();
intradayTradePosition.id = intradayTradePositions[i].id;
db.Entry(intradayTradePositions[i]).CurrentValues.SetValues(intradayTradePosition);
}
//删除不该存在的场外交易,例如到期日被修改到了今天之前的某一天
var intradayTradePositionDelete = db.intraday_trade_position.Where(x => !tradeids.Contains(x.TradeId) && x.TradeId > 0).ToList();
if (intradayTradePositionDelete.Any())
{
db.intraday_trade_position.RemoveRange(intradayTradePositionDelete);
}
db.SaveChanges();
return realtimePositionList;
}
}
}
/// <summary>
/// 计算实时持仓并返回结果
/// </summary>
public static List<ClientPosition> RealtimeSwapPosition(OptUserInfo optUser)
{
string bondCalcTopic = Environment.GetEnvironmentVariable("KafkaConfig_ReqCalcBondTopic");
bool.TryParse(Environment.GetEnvironmentVariable("KafkaConfig_EnableCalcBongd"), out bool enableCalcBongd);
if (optUser is null)
{
throw new ArgumentNullException(nameof(optUser));
}
RestInitData();
lock (_RefrshLock)
{
using (var db = new YLContext())
{
#region 获取当前持仓 标的当前价格 当前未簿记流水 并计算Risk信息
//标的
var underlyingPrice = DataCacheProvider.GetUnderlyingDataSource();
//获取待计算交列表
var tradeList = db.trade.AsNoTracking().Where(t => t.ValidState != "InValid" && t.TradeDate <= _ValueDate//有效的交易
&& (ConsTrade.NeedMarginTradeStatusList.Contains(t.TradeStatus))
&& t.TradeType == "收益互换").ToList();
//OTC持仓交易
var tradeIdList = tradeList.Select(t => t.id).ToList();
var positions = db.swap_position.Where(x => tradeIdList.Contains(x.SwapTradeId) && !x.IsInitial && x.PosiQuantity > 0&&!x.Invalid).ToList();
var swapFlows = db.swap_flow.Where(x => x.DataState == (int)SwapFlowDateStateEnum.等待完成).ToList();
using var bondDb = new BondOmsDBContext();
var clientPositions = bondDb.client_position.AsEnumerable();
var eodSwaps = db.eod_swap_position.Where(x => tradeIdList.Contains(x.SwapTradeId) && x.PosiDirection > 0).AsEnumerable().GroupBy(p => p.SwapTradeId)
.Select(g => g.OrderByDescending(p => p.ValueDate).First()).ToList();
#endregion
#region 实时持仓计算
//实时结果对象类
var realtimePositionList = new List<ClientPosition>();
#endregion
#region 当日持仓期权交易 以及当前交易流水计算持仓
var query = from td in tradeList
join p in positions on td.id equals p.SwapTradeId
select new
{
td,
p
};
var positionGroup = query.AsEnumerable().GroupBy(x => new { x.p.UnderlyingCode, x.td.ClientId,x.p.PosiDirection});
var dealSwapFlowIds = new List<long>();
SwapTradeAutoService swapTradeAutoService = new SwapTradeAutoService(optUser);
var datenow = DateTime.Now;
foreach (var pair in positionGroup)
{
var client = DataCacheProvider.GetClientDataSource().GetData(pair.Key.ClientId);
if (client == null||string.IsNullOrEmpty(pair.Key.UnderlyingCode))
{
continue;
}
var clientPosition = clientPositions.FirstOrDefault(x => x.client_id == pair.Key.ClientId && x.security_id == pair.Key.UnderlyingCode&&x.direction== pair.Key.PosiDirection);
var trades = pair.Select(s => s.td).ToList();
var tradeIds = trades.Select(x => x.id);
var positionGroupItems = positions.Where(x => tradeIds.Contains(x.SwapTradeId) && x.UnderlyingCode == pair.Key.UnderlyingCode && x.PosiDirection == pair.Key.PosiDirection);
var lastEodSwaps = eodSwaps.Where(x => tradeIds.Contains(x.SwapTradeId)).ToList();
var lastPv = lastEodSwaps.Sum(s => s.UnderlyingMarketValue);
if (!positionGroupItems.Any())
{
continue;
}
var comminsions = positionGroupItems.Sum(s => s.PosiTradingFeePending);
var lastPosi = positionGroupItems.OrderByDescending(x => x.id).First();
var newSwapFlows = swapFlows.Where(x => x.ClientId == pair.Key.ClientId && x.UnderlyingCode == pair.Key.UnderlyingCode).ToList();
var cunrentPositions = positionGroupItems.Sum(x => x.PosiQuantity * (x.PositionType == (int)PositionTypeFlag.Long ? 1 : -1));
var positionType = cunrentPositions > 0 ? PositionTypeFlag.Long : PositionTypeFlag.Short;
var posiQty = Math.Abs(cunrentPositions);
var multiplier = ConsGlobal.InstrumentType.IsBond(lastPosi.UnderlyingInstrumentType) ? ConsGlobal.bondShowPriceMultiple : 1;
// 计算加权平均价格(区分债券和非债券)
var weightedPrice = posiQty==0?0: positionGroupItems
.Sum(s => {
decimal price = ConsGlobal.InstrumentType.IsBond(lastPosi.UnderlyingInstrumentType)
? s.PosiGrossPrice * ConsGlobal.bondShowPriceMultiple
: s.PosiGrossPrice;
return s.PosiQuantity * price;
}) / posiQty;
var weightedNetPrice = posiQty==0?0: positionGroupItems
.Sum(s => {
decimal price = ConsGlobal.InstrumentType.IsBond(lastPosi.UnderlyingInstrumentType)
? s.PosiNetPrice * ConsGlobal.bondShowPriceMultiple
: s.PosiNetPrice;
return s.PosiQuantity * price;
}) / posiQty;
// 替换原代码中的 price 和 netPrice
var price = weightedPrice;
var netPrice = weightedNetPrice;
var totalNotional = positionGroupItems.Sum(s => s.PosiNotionalValue);
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(pair.Key.UnderlyingCode);
clientPosition = CreateClientPosition(clientPosition, pair.Key.ClientId, pair.Key.UnderlyingCode, netPrice, price, posiQty / 10000, comminsions, positionType == PositionTypeFlag.Long ? 0 : 1, lastPosi.ContractSize, pair.Key.PosiDirection);
clientPosition.position_notional_principal = totalNotional;
if (pair.Key.PosiDirection==(int)SwapDirectionEnum.支付)
{
var flowMerges = MergeSwapFlow(newSwapFlows, multiplier);
dealSwapFlowIds.AddRange(newSwapFlows.Select(s => s.id));
if (flowMerges.Any())
{
MergeSwapPosition(flowMerges, positionType, clientPosition, posiQty);
}
}
clientPosition.update_user = 0;
SetClientPositionPrice(clientPosition);
clientPosition.swap_market_value = clientPosition.full_price_now * clientPosition.position_qty * (clientPosition.side == 0 ? 1 : -1);
clientPosition.position_profit_loss = (clientPosition.full_price_now - clientPosition.deal_full_price_avg) * clientPosition.position_qty * (clientPosition.side == 0 ? 1 : -1) - clientPosition.commission;
clientPosition.position_profit_loss = Math.Round(clientPosition.position_profit_loss ?? 0, 2, MidpointRounding.AwayFromZero);
clientPosition.today_profit_loss = clientPosition.swap_market_value - lastPv;
if (clientPosition.deal_full_price_avg > 0 && enableCalcBongd)//发kafka 获取成交收益率
{
BondCalcApi(clientPosition);
}
if (clientPosition.id == 0 && clientPosition.position_qty > 0)
{
clientPosition.update_time = DateTime.Now;
bondDb.client_position.Add(clientPosition);
}
else if (clientPosition.id > 0 && (clientPosition.position_qty > 0 || clientPosition.today_profit_loss != 0))
{
clientPosition.update_time = DateTime.Now;
}
bondDb.SaveChanges();
}
var sql = $"{nameof(ClientPosition.create_time)}<'{datenow.AddSeconds(-1):yyyy-MM-dd HH:mm:ss}' or {nameof(ClientPosition.position_qty)}=0";
bondDb.BulkDelete<ClientPosition>(sql);
bondDb.SaveChanges();
var nodealSwapFlows = swapFlows.Where(x => !dealSwapFlowIds.Contains(x.id));
if (nodealSwapFlows.Any())
{
var nodealSwapFlowGroup = nodealSwapFlows.AsEnumerable().GroupBy(g => new { g.ClientId, g.UnderlyingCode });
foreach (var swapFlowGroup in nodealSwapFlowGroup)
{
var client = DataCacheProvider.GetClientDataSource().GetData(swapFlowGroup.Key.ClientId ?? 0);
if (client == null)
{
continue;
}
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(swapFlowGroup.Key.UnderlyingCode);
var multiplier = um!=null&& um.IsBond() ? ConsGlobal.bondShowPriceMultiple : 1;
var flowMerges = MergeSwapFlow(swapFlowGroup.ToList(), multiplier);
var flowMergeMax = flowMerges.OrderByDescending(s => s.TradingQty).First();
var flowMergeMin = flowMerges.FirstOrDefault(x => x.BsType != flowMergeMax.BsType);
var comminsions = flowMerges.Sum(s => s.TradingFee);
var qty = flowMergeMax.TradingQty;
if (flowMergeMin != null)
{
qty -= flowMergeMin.TradingQty;
}
var clientPosition = clientPositions.FirstOrDefault(x => x.client_id == swapFlowGroup.Key.ClientId && x.security_id == swapFlowGroup.Key.UnderlyingCode);
clientPosition = CreateClientPosition(clientPosition, swapFlowGroup.Key.ClientId ?? 0, swapFlowGroup.Key.UnderlyingCode, flowMergeMax.TradingAmountNetAvg ?? 0, flowMergeMax.TradingAmountAvg, qty / 10000, comminsions, flowMergeMax.BsType == (int)PositionTypeFlag.Long ? 0 : 1, flowMergeMax.ContractSize, (int)SwapDirectionEnum.支付);
clientPosition.position_qty = qty / 10000;
clientPosition.update_user = 0;
if (clientPosition.id == 0)
{
clientPosition.update_time = DateTime.Now;
bondDb.client_position.Add(clientPosition);
}
SetClientPositionPrice(clientPosition);
clientPosition.swap_market_value = clientPosition.full_price_now * clientPosition.position_qty * (clientPosition.side == 0 ? 1 : -1);
clientPosition.position_profit_loss = (clientPosition.full_price_now - clientPosition.deal_full_price_avg) * clientPosition.position_qty * (clientPosition.side == 0 ? 1 : -1);
clientPosition.position_profit_loss = Math.Round(clientPosition.position_profit_loss ?? 0, 2, MidpointRounding.AwayFromZero);
clientPosition.today_profit_loss = clientPosition.swap_market_value;
//发kafka 获取成交收益率
if (clientPosition.deal_full_price_avg > 0 && enableCalcBongd)
{
CalcBandPrice(clientPosition);
}
else if (clientPosition.id > 0 && (clientPosition.position_qty > 0 || clientPosition.today_profit_loss != 0))
{
clientPosition.update_time = DateTime.Now;
}
bondDb.SaveChanges();
}
}
sql = $"{nameof(ClientPosition.create_time)}<'{datenow.AddSeconds(-1):yyyy-MM-dd HH:mm:ss}' or {nameof(ClientPosition.position_qty)}=0";
bondDb.BulkDelete<ClientPosition>(sql);
bondDb.SaveChanges();
#endregion
return realtimePositionList;
}
}
}
/// <summary>
/// 判断是否有新流水
/// </summary>
/// <param name="calcTime"></param>
/// <returns></returns>
public static bool HasNewFlow(DateTime calcTime)
{
using (var db = new YLContext())
{
return db.swap_flow.Any(x => x.OptTime >= calcTime);
}
}
/// <summary>
/// 计算RealtimeRisk
/// </summary>
public static void RiskCalc()
{
lock (_RefrshLock)
{
using (var db = new YLContext())
{
RestInitData();
#region 获取当前持仓 标的当前价格 当前未簿记流水 并计算Risk信息
//标的
var underlyingPrice = DataCacheProvider.GetUnderlyingDataSource();
//获取待计算交列表
var tradeList = _TradeSwapList;
//OTC持仓交易
//实时计算rsik
var volTypes = new List<string> { "持仓" };
var riskList = RealTimeRiskCalc(_ValueDate, tradeList, underlyingPrice, volTypes);
#endregion
}
}
}
/// <summary>
/// DMA预付金计算
/// </summary>
public static void CalcDMAMargin()
{
var baseUrl = Environment.GetEnvironmentVariable("BondOmsInterface_BaseUrl");
var calculateMarginUrl = "/marginAlgorithm/realTimeMarginCalc";
var balanceDate = valuedateBLL.ValueDate;
var preSettleDate = BLL.valuedateBLL.GetNonHolidayDefore(balanceDate.AddDays(-1));
CalculateMarginRequest request = new CalculateMarginRequest()
{
currentDate = balanceDate.ToString("yyyy-MM-dd"),
preSettleDate = preSettleDate.ToString("yyyy-MM-dd")
};
if (!string.IsNullOrEmpty(baseUrl))
{
var httpHelper = new HttpHelper(baseUrl, null);
// http 请求 Web项目接口
var result = httpHelper.PostRequestNoAuth<CalculateMarginRequest, CalculateMarginResponse>(calculateMarginUrl, request).Result;
if (result != null && !result.success)
{
LogFactory.GetLogger("DMA预付金计算").Info("互换DMA预付金计算失败:" + result.message);
}
}
}
#region 新互换实时持仓私有方法
private static void BondCalcApi(ClientPosition clientPosition)
{
var resp = BondCalcHepler.BondCalc(clientPosition.security_id, clientPosition.deal_full_price_avg ?? 0, "DP");
if (resp!=null)
{
clientPosition.deal_yield_avg = resp.ytm* ConsGlobal.bondPriceMultiple;
_yLCache.StringSetWithNoPrefix<CalBondResult>("TRS-BondFullPrice:" + clientPosition.security_id, resp,TimeSpan.FromHours(1));
}
}
/// <summary>
/// 创建持仓
/// </summary>
/// <param name="clientId"></param>
/// <param name="underlyingCode"></param>
/// <param name="underlyingName"></param>
/// <param name="price"></param>
/// <param name="fullPrice"></param>
/// <param name="qty"></param>
/// <param name="comminsion"></param>
/// <param name="side"></param>
/// <returns></returns>
private static ClientPosition CreateClientPosition(ClientPosition clientPosition, int clientId, string underlyingCode, decimal price, decimal fullPrice, decimal qty, decimal comminsion, int side,decimal contractsize,int direction)
{
var underlyingName = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode)?.UnderlyingName;
var client = DataCacheProvider.GetClientDataSource().GetData(clientId);
if (clientPosition == null)
{
clientPosition = new ClientPosition()
{
create_time = DateTime.Now,
};
}
clientPosition.client_id = clientId;
clientPosition.client_name = client?.Name;
clientPosition.security_id = underlyingCode;
clientPosition.symbol = underlyingName;
clientPosition.deal_price_avg = price;
clientPosition.deal_full_price_avg = fullPrice;
clientPosition.position_qty = qty;
clientPosition.commission = comminsion;
clientPosition.side = side;
clientPosition.create_time = DateTime.Now;
clientPosition.client_user_id = 0;
clientPosition.position_notional_principal = fullPrice* qty * 10000 * contractsize * ConsGlobal.bondPriceMultiple;
clientPosition.direction = direction;
return clientPosition;
}
/// <summary>
/// 合并互换流水
/// </summary>
/// <param name="swapFlows"></param>
/// <returns></returns>
private static List<swap_flow_merge> MergeSwapFlow(List<swap_flow> swapFlows, decimal multiplier)
{
List<swap_flow_merge> list = new List<swap_flow_merge>();
var newSwapFlowsGroups = swapFlows.GroupBy(g => g.BsType);
foreach (var gourpItem in newSwapFlowsGroups)
{
var swapflow = gourpItem.First();
swap_flow_merge swap_flow_summary = new swap_flow_merge()
{
OccurTime = swapflow.OccurTime.Value,
FundAccount = swapflow.FundAccount,
SwapTradeId = swapflow.SwapTradeId,
SwapTradeNo = swapflow.SwapTradeNo,
UnderlyingCode = swapflow.UnderlyingCode,
BsType = swapflow.BsType,
TradingQty = gourpItem.Sum(s => s.TradingQty),
TradingFeePending = gourpItem.Sum(s => s.TradingFee),
DataState = (int)SwapFlowDateStateEnum.等待完成,
ContractSize = swapflow.ContractSize,
ClientId = swapflow.ClientId,
TradingAmount = gourpItem.Sum(s => s.TradingAmount)
};
int tradeSide = swap_flow_summary.BsType == (int)EnumDirection.Long ? 1 : -1;
swap_flow_summary.FirstFlowTime = swapflow.OptTime;
swap_flow_summary.SettleDate = gourpItem.Max(s => s.SettleDate);
swap_flow_summary.TradingAmountAvg = swap_flow_summary.TradingQty == 0 ? 0 : gourpItem.Sum(s => s.TradingAmountAvg * s.TradingQty) / swap_flow_summary.TradingQty;
swap_flow_summary.TradingAmountAvg = Math.Round(swap_flow_summary.TradingAmountAvg, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero);
swap_flow_summary.TradingAmountFeeAvg = swap_flow_summary.TradingQty == 0 ? swap_flow_summary.TradingAmountAvg : swap_flow_summary.TradingAmountAvg + swap_flow_summary.TradingFeePending * tradeSide / swap_flow_summary.TradingQty;
swap_flow_summary.TradingAmountFeeAvg = Math.Round(swap_flow_summary.TradingAmountFeeAvg, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero);
swap_flow_summary.TradingAmountNetAvg = swap_flow_summary.TradingQty == 0 ? 0 : gourpItem.Sum(s => s.TradingAmountNet * s.TradingQty) / swap_flow_summary.TradingQty;
swap_flow_summary.TradingAmountNetAvg = Math.Round(swap_flow_summary.TradingAmountNetAvg ?? 0, ConsGlobal.PriceRound);
swap_flow_summary.TradingAmountNetFeeAvg = swap_flow_summary.TradingQty == 0 ? swap_flow_summary.TradingAmountNetAvg : swap_flow_summary.TradingAmountNetAvg + swap_flow_summary.TradingFeePending * tradeSide / swap_flow_summary.TradingQty;
swap_flow_summary.TradingAmountNetFeeAvg = Math.Round(swap_flow_summary.TradingAmountNetFeeAvg ?? 0, ConsGlobal.PriceRound);
swap_flow_summary.TradingAmountAvg *= multiplier;
swap_flow_summary.TradingAmountFeeAvg *= multiplier;
list.Add(swap_flow_summary);
}
return list.OrderByDescending(o => o.TradingQty).ToList();
}
/// <summary>
/// 流水合并持仓
/// </summary>
/// <param name="flowMerges"></param>
/// <param name="positionType"></param>
/// <param name="clientPosition"></param>
/// <param name="posiQty"></param>
private static void MergeSwapPosition(List<swap_flow_merge> flowMerges, PositionTypeFlag positionType, ClientPosition clientPosition, decimal posiQty)
{
var flowMergeSame = flowMerges.FirstOrDefault(x => x.BsType == (int)positionType);
var flowMergeNagetive = flowMerges.FirstOrDefault(x => x.BsType != (int)positionType);
var sameQty = posiQty;
if (flowMergeSame != null)
{
sameQty += flowMergeSame.TradingQty;
}
var allPosiQty = sameQty;
if (flowMergeNagetive != null)
{
allPosiQty -= flowMergeNagetive.TradingQty;
if (allPosiQty >= 0)
{
var priceResult = CalcWeightedAverage(clientPosition, flowMergeSame);
clientPosition.deal_full_price_avg = priceResult.Item1;
}
else
{
clientPosition.deal_full_price_avg = flowMergeNagetive.TradingAmountAvg;
}
}
else
{
var priceResult = CalcWeightedAverage(clientPosition, flowMergeSame);
clientPosition.deal_full_price_avg = priceResult.Item1;
}
clientPosition.commission = flowMerges.Sum(s => s.TradingFee);
clientPosition.position_qty = Math.Abs(allPosiQty/10000);
clientPosition.position_notional_principal = Math.Abs(allPosiQty) * clientPosition.deal_full_price_avg * ConsGlobal.bondPriceMultiple;
if (allPosiQty < 0)
{
clientPosition.side = clientPosition.side == 0 ? 1 : 0;
}
}
private static (decimal, decimal) CalcWeightedAverage(ClientPosition clientPosition, swap_flow_merge flowMergeSame)
{
var originalAmount = (clientPosition.deal_full_price_avg ?? 0) * (clientPosition.position_qty ?? 0);
var originalNetAmount = (clientPosition.deal_price_avg ?? 0) * (clientPosition.position_qty ?? 0);
if (flowMergeSame == null)
{
return (clientPosition.deal_full_price_avg ?? 0, clientPosition.deal_price_avg ?? 0);
}
var sameAmount = flowMergeSame.TradingAmountAvg * flowMergeSame.TradingQty;
var sameNetAmount = (flowMergeSame.TradingAmountNetAvg??0) * flowMergeSame.TradingQty;
var totalQty = (clientPosition.position_qty ?? 0) + flowMergeSame.TradingQty;
if (totalQty == 0)
{
return (0, 0);
}
var price = (originalAmount + sameAmount) / totalQty;
var priceFee = (originalNetAmount + sameNetAmount) / totalQty;
price = Math.Round(price, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero);
priceFee = Math.Round(priceFee, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero);
return (price, priceFee);
}
/// <summary>
/// 从缓存中拿取债券价格
/// </summary>
/// <param name="clientPosition"></param>
private static void SetClientPositionPrice(ClientPosition clientPosition)
{
if (clientPosition.position_qty <= 0)
{
return;
}
try
{
//TRS-BondDepthMarket:160010.IB-0
var bondPrice = EodPriceQueryService.GetChinaBondPrice(valuedateBLL.ValueDate, clientPosition.security_id);
if (bondPrice != null)
{
clientPosition.full_price_now = bondPrice.dirty_price_close;
clientPosition.swap_market_value = clientPosition.full_price_now * clientPosition.position_qty * 10000 * (clientPosition.side == 0 ? 1 : -1) * ConsGlobal.bondPriceMultiple;
clientPosition.position_profit_loss = (clientPosition.full_price_now - clientPosition.deal_full_price_avg) * clientPosition.position_qty * 10000 * ConsGlobal.bondPriceMultiple * (clientPosition.side == 0 ? 1 : -1);
clientPosition.price_now = bondPrice.net_price;
clientPosition.yield_now = bondPrice.yield * ConsGlobal.bondPriceMultiple;
}
else
{
clientPosition.full_price_now = 100;
clientPosition.swap_market_value = clientPosition.full_price_now * clientPosition.position_qty * 10000 * (clientPosition.side == 0 ? 1 : -1) * ConsGlobal.bondPriceMultiple;
clientPosition.position_profit_loss = (clientPosition.full_price_now - clientPosition.deal_full_price_avg) * clientPosition.position_qty * 10000 * ConsGlobal.bondPriceMultiple * (clientPosition.side == 0 ? 1 : -1);
clientPosition.price_now = 100;
clientPosition.yield_now = 0.01m;
}
}
catch (Exception ex)
{
}
}
/// <summary>
/// 计算债券价格
/// </summary>
/// <param name="clientPosition"></param>
private static void CalcBandPrice(ClientPosition clientPosition)
{
if (clientPosition.position_qty <= 0 || _yLCache == null)
{
return;
}
try
{
//TRS-BondDepthMarket:160010.IB-0
CalBondResult bondPrice = _yLCache.StringGetWithNoPrefix<CalBondResult>("TRS-BondFullPrice:" + clientPosition.security_id);
if (bondPrice?.dirtyPrice != clientPosition.deal_full_price_avg)
{
BondCalcApi(clientPosition);
}
}
catch (Exception ex)
{
}
}
#endregion
/// <summary>
/// 实时risk计算
/// </summary>
public static List<realtime_trade_risk> RealTimeRiskCalc(DateTime valueDate, List<trade> tradeList, IPriceProvider priceProvider, List<string> volTypes = null, bool useSave = true, PricingRequest pricingRequest = QdpPricingRequest.BASIC_GREEKS)
{
// LogFactory.GetLogger<RealtimePnlCalc>().Info("CalcTradeValue Run Time:" + DateTime.Now.ToString());
//获取所有已确认交易信息
using (var db = new YLContext())
{
var risks = new List<realtime_trade_risk>();
if (tradeList == null || !tradeList.Any())
{
return risks;
}
//计算Risk
if (volTypes == null || !volTypes.Any())
{
volTypes = new List<string> { ConsGlobal.VolType.PositionVol };
}
var tradeIds = tradeList.Select(t => t.id).ToList();
var tradeCashList = db.trade_cash.AsNoTracking().Where(t => t.ValidState != "InValid" && !t.IsDeleted && tradeIds.Contains(t.TradeId) && (t.Action == ClientCashInCashOut.系统操作_平仓费 || t.Action == ClientCashInCashOut.系统操作_行权费)).ToList();
foreach (var volType in volTypes)
{
var resultRisks = new List<realtime_trade_risk>();
var isUseTradeVol = (volType == "持仓" || volType == "对冲") && PS.Config.IsTradeVol;
var tradeRiskResult = CalculatorHelper.CalculateRisksForTrades(new CalculateRisksForTradesReq
{
valueDate = valueDate,
tradeList = tradeList,
priceProvider = priceProvider,
pricingRequest = pricingRequest,
volType = volType,
isUseTradeVol = isUseTradeVol,
addVolRateDic = null,
isAddVolPercent = true,
isMarginCalc = false,
overrideVolsForTrade = null,
PreciseTimeMode = true,
calcScenario = Enums.CalcScenarioEnum.RealtimePosition,
canUseManual = true
});
if (tradeRiskResult != null)
{
var eodForwardMargins = db.eod_forward_margin.Where(x => x.ValueDate == valueDate && tradeIds.Contains(x.TradeId)).ToList();
var forwards = db.trade_forward.Where(n => tradeIds.Contains(n.TradeId)).ToList();
foreach (var result in tradeRiskResult.Results)
{
try
{
var tempTradeCashList = tradeCashList.Where(t => t.TradeId == result.Trade.id).ToList();
var pnl = 0.0;// 当日盈亏
var tradePosition = _LastTradePositionList.FirstOrDefault(t => t.TradeId == result.Trade.id);
if (tradePosition != null)
{
pnl = (double.IsNaN(result.ValueResult.Pv) ? 0.0 : (result.ValueResult.Pv)) - Convert.ToDouble(tradePosition.Pv);
}
else
{
//var futureCommission = tradeCommissionDict.ContainsKey(result.Trade.id) ? tradeCommissionDict[result.Trade.id] : 0;
var isUnOption = ConsTrade.TradeTypesForHedge.Contains(result.Trade.TradeType);
var cost = (isUnOption ? (result.Trade.TradePrice ?? 0.0) : (result.Trade.TradeSinglePrice ?? 0)) * result.Trade.Notional;
if (result.Trade.TradeType == "远期")
{
pnl = NumberHelper.Normalize(result.ValueResult.Pv) + cost;// - futureCommission;
}
else
{
pnl = NumberHelper.Normalize(result.ValueResult.Pv) + cost * TradeCalcHelper.GetSign(result.Trade.BuySell) * -1;// - futureCommission;
}
}
for (var i = 0; i < result.Underlyings.Length; ++i)
{
resultRisks.Add(createRisk(result.Trade, valueDate, result.Underlyings[i], null, volType, result.ValueResult, pnl, i, priceProvider.GetPrice(result.Trade.UnderlyingCode), tempTradeCashList, eodForwardMargins, forwards));
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
}
}
}
if (useSave)
{
//删除非交易日当天的实时持仓数据
var sql = $"{nameof(realtime_trade_risk.ValueDate)}!='{valueDate.ToSqlDate()}'";
db.BulkDelete<realtime_trade_risk>(sql);
//插入数据库还未有过的实时持仓服务计算的数据(根据TradeId,VolType,ValueDate筛选)
var tradeIdsExist = db.realtime_trade_risk.Where(x => x.VolType == volType && x.ValueDate == valueDate).Select(x => x.TradeId).ToList();
var resultRisksInsert = resultRisks.Where(x => !tradeIdsExist.Contains(x.TradeId));
MySqlBulkExtensions.BulkInsert(db, resultRisksInsert);
//根据TradeId,VolType,ValueDate更新已经存在的数据
var tradeids = resultRisks.Select(t => t.TradeId).ToList();
var tradeRisks = db.realtime_trade_risk.Where(x => tradeids.Contains(x.TradeId) && x.VolType == volType && x.ValueDate == valueDate).ToList();
var delTradeRisks= db.realtime_trade_risk.Where(x => !tradeids.Contains(x.TradeId) && x.VolType == volType && x.ValueDate == valueDate).ToList();
db.realtime_trade_risk.RemoveRange(delTradeRisks);
for (var i = 0; i < tradeRisks.Count; i++)
{
var tradeRisk = resultRisks.FirstOrDefault(x => x.TradeId == tradeRisks[i].TradeId)?.Clone();
tradeRisk.id = tradeRisks[i].id;
db.Entry(tradeRisks[i]).CurrentValues.SetValues(tradeRisk);
}
db.SaveChanges();
}
if (volType == "持仓")
{
risks = resultRisks;
}
}
return risks;
}
}
/// <summary>
/// 刷新RealTimeRisk表对应交易记录和实时持仓信息(适用于OTC场内期权交易)
/// </summary>
public static void RefreshRiskAndIntradayPositionForOtc(List<trade> tradeList, OptUserInfo user)
{
if (tradeList is null)
{
throw new ArgumentNullException(nameof(tradeList));
}
if (user is null)
{
throw new ArgumentNullException(nameof(user));
}
if (tradeList != null && tradeList.Any())
{
new TradeDalService(user).SetSubTradeList(tradeList);
using (var db = new YLContext())
{
RestInitData();
//获取停牌信息
var suspensionUnderlyingIdList = underlying_managerBLL.GetQuery().Where(t => t.UnderlyingStatus == underlying_manager.Status_Suspension).Select(t => t.id).ToList();
#region 获取昨日持仓 标的当前价格 当前持仓以及当日行权交易 并计算Risk信息
var clientTrades = db.trade.AsNoTracking().Where(t => t.ValidState != "InValid" && t.TradeDate <= valuedateBLL.ValueDate//有效的交易
&& ((ConsTrade.LiveTradeStatusList.Contains(t.TradeStatus) && (t.ExerciseDate >= _ValueDate || (suspensionUnderlyingIdList.Contains(t.UnderlyingId) && !ConsTrade.TradeTypesForHedge.Contains(t.TradeType))) && !ConsTrade.TradeTypesForHedge.Contains(t.TradeType)) //未过期的(包括股票停牌)期权持仓交易
|| (t.TradeDate > _LastSettleDate && ConsTrade.TradeTypesForHedge.Contains(t.TradeType)) //最后结算日到当日介于区间的对冲交易
|| (t.UnWindDate > _LastSettleDate && t.UnWindDate <= _ValueDate && ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus)) //最后结算日到当日区间内平仓到期执行的交易
)
&& ConsTrade.TradeTypesForOtcOptions.Contains(t.TradeType)).ToList();
//昨日持仓交易
var tradeIdList = tradeList.Select(t => t.id).ToList();
var underlyingIds = tradeList.Select(t => t.UnderlyingId).Distinct().ToList();
//标的
var underlyingPrice = DataCacheProvider.GetUnderlyingDataSource();
//设置option info
tradeBLL.SetFieldsByTradeType(tradeList);
//OTC 交易
var otcTradeList = tradeList.Where(t => t.TradeType != "结构化交易" && t.ClientId > 0).ToList();
//预付金计算
//远期不参与计算预付金逻辑
var req = new RunMarginCalculationReq(user)
{
tradeList = otcTradeList,
settleDate = _ValueDate,
PriceProvider = underlyingPrice,
hasOptionInfo = true
};
var tradeSpans = MarginDefault.RunMarginCalculation(req.Clone(forOtherSide: false));
//试算出交易买卖方向反向的tradeSpan(目前只有国君有这个需求,做过处理)
List<trade_span> tradeSpansOtherSide = new List<trade_span>();
if (MarginDefault.IsMarginCalcNeedSpecial(_ValueDate))
{
//试算出交易买卖方向反向的tradeSpan(目前只有国君有这个需求,做过处理)
tradeSpansOtherSide = MarginDefault.RunMarginCalculation(req.Clone(forOtherSide: true));
}
//根据交易预付金合计客户预付金计入client_span
var req2 = new CalcClientMarginReq(user)
{
settleDate = _ValueDate,
tradeSpans = tradeSpans,
tradeSpansOtherSide = tradeSpansOtherSide,
SpanType = ClientSpan.SpanType_RealTime
};
MarginDefault.CalcClientMargin(req2);
//实时计算rsik
var volTypes = new List<string> { "持仓" };
if (PS.Config.Is国投)
{
volTypes.Add("开仓");
}
var riskList = RealTimeRiskCalc(_ValueDate, otcTradeList, underlyingPrice, volTypes);
#endregion
#region 平仓费行权费 交易预付金计算 昨日持仓对冲交易过滤
var unWindTradeCashAction = new List<string> { ClientCashInCashOut.系统操作_平仓费, ClientCashInCashOut.系统操作_行权费, ClientCashInCashOut.系统操作_期权费 };
//获取平仓到期交易的trade_cash;
var tradeCashList = db.trade_cash.Where(t => tradeIdList.Contains(t.TradeId) && unWindTradeCashAction.Contains(t.Action) && !t.IsDeleted).ToList();
//实时结果对象类
var realtimePositionList = new List<intraday_trade_position>();
#endregion
#region 当日持仓期权交易 已行权已到期期权交易 以及当日对冲交易计算持仓
//循环交易 OTC交易
otcTradeList.ForEach(t =>
{
var Pv = 0.0; //当日pv
var RoundedPv = 0.0;
var LastPv = 0.0; //昨日pv
var Quantity = 0.0; //数量
var RealizedPnL = 0.0;//已归因盈亏
var DailyPnl = 0.0; //当日盈亏
var UnRealizedPnL = 0.0;//未归因盈亏
var TotalPnL = 0.0; //总盈亏
var PositionPnL = 0.0; //持仓盈亏
var RoundedPositionPnL = 0.0;
var NotionalPrincipal = 0.0;
var ActualPv = 0.0; //当日实际pv
var ActualLastPv = 0.0; //昨日实际pv
var ActualDailyPnl = 0.0; //当日实际浮动盈亏
var ActualTotalPnL = 0.0; //实际总盈亏
//部分平仓计算
var tempTradeCashList = tradeCashList.Where(a => a.TradeId == t.id);
//已实现
var RealizeProfitAndloss = (tempTradeCashList.Any() ? tempTradeCashList.Sum(a => a.Amount) : 0.0);
//预付金
var tradeSpan = tradeSpans.FirstOrDefault(a => a.TradeId == t.id);
//已实现盈亏
var positionRealizedTradeCashs = db.trade_cash.Where(x => (x.Action == "系统操作-票息" || x.Action == "系统操作-互换") && t.ValidState != "InValid" && x.ValueDate <= _ValueDate && (x.TradeId == t.id || x.ParentTradeId == t.id)).ToList();
if (ConsTrade.LiveTradeStatusList.Contains(t.TradeStatus))
{
if (riskList.Any(a => a.TradeId == t.id))
{
var openValueResult = riskList.FirstOrDefault(a => a.TradeId == t.id && a.VolType == "开仓");
if (PS.Config.Is国投 && openValueResult != null)
{
Pv = openValueResult.Pv ?? 0;
RoundedPv = openValueResult.RoundedPv ?? 0;
PositionPnL = openValueResult.PositionPnl ?? 0;
RoundedPositionPnL = openValueResult.RoundedPositionPnl ?? 0;
}
else
{
var valueResult = riskList.FirstOrDefault(a => a.TradeId == t.id);
Pv = valueResult.Pv ?? 0;
RoundedPv = valueResult.RoundedPv ?? 0;
PositionPnL = valueResult.PositionPnl ?? 0;
RoundedPositionPnL = valueResult.RoundedPositionPnl ?? 0;
}
}
else
{
Pv = 0.0;
RoundedPv = 0.0;
}
//var valueResult = holdRisResult.ContainsKey(t.id) ? holdRisResult[t.id] : null;
//if (valueResult == null) continue;
var lastEodPosition = _LastTradePositionList.FirstOrDefault(e => e.TradeId == t.id);
//if (lastEodPosition != null) _LastTradePositionList.Remove(lastEodPosition);
//昨日pv
LastPv = lastEodPosition == null ? 0 : Convert.ToDouble(lastEodPosition.Pv);
//ActualLastPv = lastEodPosition == null ? 0 : Convert.ToDouble(lastEodPosition.ActualPv ?? 0.0);
//总持仓量
Quantity = lastEodPosition == null ? t.Notional : lastEodPosition.Amount;
//归因盈亏
RealizedPnL = lastEodPosition != null ? 0 : ((t.TradeSinglePrice ?? 0) * t.Notional * TradeCalcHelper.GetSign(t.BuySell) * (-1));
//未归因盈亏
UnRealizedPnL = Pv - LastPv;
//估值盈亏
DailyPnl = RealizedPnL + UnRealizedPnL;
//名义本金 如果是股票则取名义本金字段 如果为商品期货则去 spotprice * 份额
NotionalPrincipal = "Stock".Equals(t.UnderlyingInstrumentType) ? t.StockEqvNotional : (t.Notional * (t.SpotPrice ?? 0.0));
//根据看涨看跌以及当前价格与行权价涨跌判断是否有实际pv
var callPutFlag = "Call".Equals(t.CallPut);
var unSpotPrice = underlyingPrice.GetPrice(t.UnderlyingCode);
var StrikeFlag = unSpotPrice > (t.IsMoneynessOptionData ? (t.Strike * t.SpotPrice) : t.Strike ?? 0.0);
//实值pv计算
ActualPv = 0.0;
if (callPutFlag == StrikeFlag)
{
var Strike = t.IsMoneynessOptionData ? ((t.Strike ?? 0.0) * t.SpotPrice ?? 0.0) : t.Strike ?? 0.0;
var SpotPrice = t.SpotPrice ?? 0;
if (SpotPrice > 0)
{
ActualPv = t.StockEqvNotional * Math.Max((unSpotPrice - Strike) * (callPutFlag ? 1 : -1), 0) / SpotPrice * TradeCalcHelper.GetSign(t.BuySell);
}
}
//实值浮动盈亏
//ActualDailyPnl = ActualPv - ActualLastPv;
//实值总盈亏
//ActualTotalPnL = (lastEodPosition == null ? 0 : lastEodPosition.ActualTotalPnL ?? 0.0) + ActualDailyPnl;
//总盈亏
TotalPnL = (lastEodPosition == null ? 0 : lastEodPosition.TotalPnL) + DailyPnl;
//PositionPnL = Pv + RealizeProfitAndloss;
}
else if (ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus))
{//已执行 已平仓 已到期的交易计算持仓信息
var tradeCash = tradeCashList.FirstOrDefault(a => a.TradeId == t.id && a.Action != ClientCashInCashOut.系统操作_期权费);
Pv = ActualPv = tradeCash == null ? 0.0 : tradeCash.Amount;
RoundedPv = Pv;
var lastEodPosition = _LastTradePositionList.FirstOrDefault(e => e.TradeId == t.id);
//if (lastEodPosition != null) _LastTradePositionList.Remove(lastEodPosition);
//昨日pv
LastPv = ActualLastPv = lastEodPosition == null ? 0 : Convert.ToDouble(lastEodPosition.Pv);
//总持仓量
Quantity = lastEodPosition == null ? t.Notional : lastEodPosition.Amount;
//归因盈亏
RealizedPnL = Pv;
//未归因盈亏
UnRealizedPnL = -LastPv;
//估值盈亏
DailyPnl = RealizedPnL + UnRealizedPnL;
//名义本金 如果是股票则取名义本金字段 如果为商品期货则去 spotprice * 份额
NotionalPrincipal = "Stock".Equals(t.UnderlyingInstrumentType) ? t.StockEqvNotional : (t.Notional * (t.SpotPrice ?? 0.0));
//根据看涨看跌以及当前价格与行权价涨跌判断是否有实际pv
//实值pv计算
ActualDailyPnl = ActualPv - ActualLastPv;
//总盈亏
ActualTotalPnL = TotalPnL = Pv - ((t.TradeSinglePrice ?? 0.0) * t.Notional * TradeCalcHelper.GetSign(t.BuySell));
TotalPnL = PositionPnL = RoundedPositionPnL = Pv + RealizeProfitAndloss;
}
var Margin = tradeSpan == null ? 0.0 : double.IsNaN(tradeSpan.WorstCastClientPayable ?? double.NaN) ? 0 : tradeSpan.WorstCastClientPayable.Value;
//收益互换 应缴预付金 初始预付金 盈亏
var SwapMargin = t.TradeType == "收益互换" ? (tradeSpan == null ? 0.0 : double.IsNaN(tradeSpan.WorstCastClientPayable ?? double.NaN) ? 0 : tradeSpan.WorstCastClientPayable.Value) : 0.0;
var SwapInitMargin = t.TradeType == "收益互换" ? (tradeSpan == null ? 0.0 : double.IsNaN(tradeSpan.SwapInitMargin ?? double.NaN) ? 0 : tradeSpan.SwapInitMargin.Value) : 0.0;
var SwapWinLoss = t.TradeType == "收益互换" ? (tradeSpan == null ? 0.0 : double.IsNaN(tradeSpan.SwapWinLoss ?? double.NaN) ? 0 : tradeSpan.SwapWinLoss.Value) : 0.0;
var SwapUnMargin = 0d;
//收益互换子交易 根据父交易预付金 按名义本金比例计算子交易预付金
if (t.TradeType == "收益互换")
{
//trade_span 追保==0 时 取客户浮亏作为互换可容忍金额
SwapUnMargin = tradeSpan == null || double.IsNaN(tradeSpan.SwapWinLoss ?? double.NaN) ? 0.0 : Math.Max(tradeSpan.Margin == 0 ? tradeSpan.SwapWinLoss.Value : 0.0, 0);
//收益互换名义本金
NotionalPrincipal = t.StockEqvNotional;
if (t.IsGroup == 2 && tradeSpans.Any(span => span.TradeId == t.ParentTradeId) && otcTradeList.Any(o => o.id == t.ParentTradeId))
{
var parentTrade = otcTradeList.Find(o => o.id == t.ParentTradeId);
var parentSpan = tradeSpans.Find(span => span.TradeId == t.ParentTradeId);
if (parentTrade.StockEqvNotional != 0)
{
SwapMargin = Margin = (parentSpan.WorstCastClientPayable ?? 0.0) * t.StockEqvNotional / parentTrade.StockEqvNotional;
SwapInitMargin = (parentSpan.SwapInitMargin ?? 0.0) * t.StockEqvNotional / parentTrade.StockEqvNotional;
SwapWinLoss = (parentSpan.SwapWinLoss ?? 0.0) * t.StockEqvNotional / parentTrade.StockEqvNotional;
}
}
}
realtimePositionList.Add(
new intraday_trade_position
{
TradeId = t.id,
TradeNumber = t.TradeNumber,
ValueDate = _ValueDate,
BookId = t.AssetId,
TradeType = t.TradeType,
ClientId = t.ClientId,
UnderlyingCode = t.UnderlyingCode,
BuySell = t.BuySell,
Cost = (t.OriginalNotional > 0 ? t.TradePrice * t.Notional / t.OriginalNotional : t.TradePrice) ?? 0,
Notional = NotionalPrincipal,
Amount = Quantity,
LastPv = (decimal)LastPv,
Pv = (decimal)Pv,
RoundedPv = (decimal)RoundedPv,
DailyPnL = (decimal)DailyPnl,
RealizedPnL = RealizedPnL,
TotalPnL = TotalPnL,
PositionPnL = PositionPnL,
RoundedPositionPnl = RoundedPositionPnL,
ActualPv = ActualPv,
ActualLastPv = ActualLastPv,
ActualDailyPnL = ActualDailyPnl,
ActualTotalPnL = ActualTotalPnL,
Margin = Margin,
PositionRelizedAmount = positionRealizedTradeCashs.Sum(x => x.Amount),
TradeStatus = t.TradeStatus,
OptDate = DateTime.Now,
OptId = user.UserId,
OptName = user.UserName,
ParentTradeId = t.ParentTradeId,
//收益互换 应缴预付金 初始预付金 盈亏
SwapInitMargin = SwapInitMargin,
SwapWinLoss = SwapWinLoss,
SwapUnMargin = SwapUnMargin
});
});
#endregion
//对冲唯一标识
//var hedgeUniqueCodeList = realtimePositionList.Where(t => trade.TradeTypesForHedge.Contains(t.TradeType)).Select(t => t.HedgeUniqueCode).ToList();
var removePosition = db.intraday_trade_position.Where(t => t.ValueDate == _ValueDate && (tradeIdList.Contains(t.TradeId)));
if (removePosition.Any())
{
db.intraday_trade_position.RemoveRange(removePosition);
}
db.intraday_trade_position.AddRange(realtimePositionList);
//if (removePosition != null) MySqlBulkExtensions.BulkDelete(db, removePosition);
//MySqlBulkExtensions.BulkInsert(db, realtimePositionList);
db.SaveChanges();
}
}
}
/// <summary>
/// 实时风险计算模型转换
/// </summary>
private static realtime_trade_risk createRisk(trade tradeObj, DateTime valueDate, underlying_manager udm, Variety variety, string volType, TradeValueResult optionValueResult, double pnl, int i, double underlyingPrice, List<trade_cash> tradeCashList, List<eod_forward_margin> eodForwardMargins, List<trade_forward> forwards)
{
//todo:感觉这个表应该加上计算时使用的期末价格
if (udm == null)
{
udm = new underlying_manager();
}
var result = new realtime_trade_risk
{
ValueDate = valueDate,
TradeId = tradeObj.id,
Exposure = udm.UnderlyingCode,
VolType = volType,
BookId = tradeObj.AssetId + "",
ClientId = tradeObj.ClientId,
Pv = NumberExtensions.Norm(optionValueResult.Pv),
RoundedPv = NumberExtensions.Norm(optionValueResult.RoundedPv),
Theta = NumberExtensions.Norm(optionValueResult.Theta),
Rho = NumberExtensions.Norm(optionValueResult.Rho),
DdeltaDt = NumberExtensions.Norm(optionValueResult.DDeltaDt),
DdeltaDvol = NumberExtensions.Norm(optionValueResult.DDeltaDVol),
DvegaDt = NumberExtensions.Norm(optionValueResult.DVegaDt),
DvegaDvol = NumberExtensions.Norm(optionValueResult.DVegaDVol),
Vol = NumberExtensions.Norm(optionValueResult.Vol),
Pnl = pnl,
OptId = 1,
OptName = "管理员",
OptDate = DateTime.Now,
Delta = NumberExtensions.Norm(optionValueResult.GetDelta(i)),
Gamma = NumberExtensions.Norm(optionValueResult.GetGamma(i)),
Vega = NumberExtensions.Norm(optionValueResult.GetVega(i)),
DeltaCash = NumberExtensions.Norm(optionValueResult.GetDeltaCash(i)),
GammaCash = NumberExtensions.Norm(optionValueResult.GetGammaCash(i)),
VegaCash = NumberExtensions.Norm(optionValueResult.VegaCash),
UnderlyingPrice = optionValueResult.SpotPrice,
};
result.DeltaInLots = TradeLotsCalc.CalcDeltaInLots(result.Delta ?? 0, variety, udm);
var pvShift = tradeObj.TradeType == "雪球期权" && tradeObj.trade_snowball.PrepaymentUsed
? -tradeObj.Notional * (tradeObj.SpotPrice ?? 0) * (tradeObj.trade_snowball.PrepaymentRatio ?? 0) * (tradeObj.BuySell == "卖出" ? -1 : 1)
: 0;
if (tradeObj.TradeType == "收益互换")
{
result.PositionPnl = optionValueResult.Pv;
result.RoundedPositionPnl = optionValueResult.RoundedPv;
}
else
{
result.PositionPnl = EodOperationBase.GetPositionPnl((result.Pv ?? 0.0) + pvShift, tradeObj.TradePrice ?? 0.0, tradeObj.Notional, tradeObj.OriginalNotional ?? 0, tradeObj.BuySell);
result.RoundedPositionPnl = EodOperationBase.GetPositionPnl((result.RoundedPv ?? 0.0) + pvShift, tradeObj.TradePrice ?? 0.0, tradeObj.Notional, tradeObj.OriginalNotional ?? 0, tradeObj.BuySell);
}
result.RealizedPnl = optionValueResult.ExtendInfo.RealPnl;
if (tradeObj.TradeType == "远期")
{
using (var db = new YLContext())
{
var marginCost = eodForwardMargins.Where(x => x.TradeId == tradeObj.id)
.Select(n => (double?)n.MarginCost).FirstOrDefault() ?? 0;
var forward = forwards.FirstOrDefault(n => n.TradeId == tradeObj.id);
var unwindTradeCashList = tradeCashList.Where(t => t.TradeId == tradeObj.id && t.ValidState != "InValid" && !t.IsDeleted && t.Action != ClientCashInCashOut.系统操作_期权费 && t.ValueDate == valueDate).ToList();
//开仓费用 + 平仓费用
var positionCost = forward.OpenCommission * (tradeObj.Lots ?? 0) + unwindTradeCashList.Sum(a => (a.UnwindPrice ?? 0) * a.UnwindNotional.Value / tradeObj.OriginalNotional.Value * (tradeObj.Lots ?? 0));
//平仓比例
double unwindRatio = unwindTradeCashList.Any() ? unwindTradeCashList.Sum(a => a.UnwindNotional.Value) / tradeObj.OriginalNotional.Value : 0;
//持仓比例
double positionRatio = 1 - unwindRatio;
//实现盈亏 = (交易已平仓) 开仓总费用 * 平仓比例 + 平仓总费用
//实现盈亏 = (交易未平仓) 0
double totalFee = unwindTradeCashList.Any() ? (tradeObj.TradePrice ?? 0) * unwindRatio + unwindTradeCashList.Sum(a => a.Amount) : 0;
//持仓市值 = 交易员视角的合约总价值(远期合约价值+开仓费用+平仓费用)-交易员视角的已实现盈亏
result.Pv = result.Pv.Value;
result.RoundedPv = result.RoundedPv.Value;
//持仓盈亏 = 持仓市值+开仓总费用 * 持仓比例
result.PositionPnl = result.Pv.Value + (tradeObj.TradePrice ?? 0) * positionRatio + marginCost;
result.RoundedPositionPnl = result.RoundedPv + (tradeObj.TradePrice ?? 0) * positionRatio + marginCost;
result.RealizedPnl = totalFee;
result.Pnl += marginCost;
}
}
double? nowPrice = 0;
if (!string.IsNullOrWhiteSpace(tradeObj.UnderlyingCode))
{
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(tradeObj.UnderlyingCode);
if (underlying == null)
{
throw new Exception($"未找到标的:{tradeObj.UnderlyingCode}");
}
else
{
nowPrice = underlying.Price;
}
}
result.CreditExposure = EodPositionRisksQueryService.ExposureCalc(tradeObj, nowPrice ?? 0, BLL.valuedateBLL.ValueDate);
if (result.UnderlyingPrice == null)
{
result.UnderlyingPrice = underlyingPrice;
}
if (tradeCashList != null && tradeCashList.Any() && tradeObj.TradeType != "远期")
{
tradeCashList.ForEach(t =>
{
result.RealizedPnl += t.Amount - ((tradeObj.TradePrice ?? 0.0) * (t.UnwindPercentRate ?? 0.0) * TradeCalcHelper.GetSign(tradeObj.BuySell));
});
}
return result;
}
/// <summary>
/// 计算客户实时资金
/// </summary>
public static List<ClientSettleBalance> GetRealTimeClientBanlance(List<int> clientIdList, DateTime? startDate = null)
{
if (null == clientIdList || !clientIdList.Any())
{
return null;
}
if (!startDate.HasValue)
{
startDate = DateTime.MinValue;
}
var cashSwapActions = new List<string>() { ClientCashInCashOut.系统操作_应付预付金, ClientCashInCashOut.系统操作_预付金返息, ClientCashInCashOut.系统操作_期权费 };
using (var db = DbContextFactory.GetYLDbContext())
using (var db2 = DbContextFactory.GetClientDbContext(null))
{
//获取系统参数
var systemDate = valuedateBLL.SystemDate;
//系统交易日
var valueDate = systemDate.ValueDate;
//客户信息
var clientList = db2.client.Where(t => clientIdList.Contains(t.id)).ToList();
var clientIds = clientList.Select(t => t.id).ToList();
var clientparentId = clientList.Select(t => t.ParentId).ToList();
//获取客户预付金(实时计算更新)
var clientSpans = db.client_span.Where(t =>
t.ValueDate == valueDate && t.SpanType == ClientSpan.SpanType_RealTime);
//获取客户昨日资金结算信息
var clientBanlances = new List<ClientBalanceDaily>();
var lastSettletDate = DateTime.MinValue;
var query = db.ClientBalanceDaily.Where(
t => t.BalanceDate < valueDate && t.BalanceDate.HasValue);
if (query.Any())
{
lastSettletDate = query.Max(t => t.BalanceDate).Value;
clientBanlances = db.ClientBalanceDaily.Where(t =>
t.BalanceDate == lastSettletDate && clientIds.Contains(t.ClientId)).ToList();
}
//获取实时持仓
var positionList = db.intraday_trade_position
.Where(t => t.ValueDate == valueDate && clientIds.Contains(t.ClientId)).ToList();
var tradeIds = positionList.Where(t => t.TradeId != 0).Select(t => t.TradeId).ToList();
var positionTrades = db.trade.AsNoTracking().Where(t => tradeIds.Contains(t.id)).ToList();
var swapFlows = db.swap_flow.Where(x => x.DataState == (int)SwapFlowDateStateEnum.等待完成 && x.OccurTime == valueDate).ToList(); ;
//获取当日所有出入金记录
var newValuedate = valueDate.AddDays(1);
var lastSettletDateAddOne = lastSettletDate.AddDays(1);
//var ClientCashList = from cash in db.ClientCashInCashOut.Where(t => t.ValidState != "InValid" && t.HappenDate >= lastSettletDateAddOne && t.HappenDate < newValuedate && (t.State == ClientCashInCashOut.已结算 || t.State == ClientCashInCashOut.已确认 || (t.Direction == "出金" && ClientCashInCashOut.outCashCals.Contains(t.State))) && clientIds.Contains(t.ClientId ?? 0))
var ClientCashList = from cash in db.ClientCashInCashOut.Where(t => t.ValidState != "InValid" && t.HappenDate >= lastSettletDateAddOne && t.HappenDate < newValuedate && (t.State == ClientCashInCashOut.已结算 || t.State == ClientCashInCashOut.已确认) && clientIds.Contains(t.ClientId ?? 0))
join trade in db.trade on cash.TradeId equals trade.id into trade
from td in trade.DefaultIfEmpty()
where td.TradeType != "收益互换"
select cash;
var ClientCashSwapList = from cash in db.ClientCashInCashOut.Where(t => t.ValidState != "InValid" && t.HappenDate >= lastSettletDateAddOne && t.HappenDate < newValuedate && (t.State == ClientCashInCashOut.已结算 || t.State == ClientCashInCashOut.已确认) && clientIds.Contains(t.ClientId ?? 0))
join trade in db.trade.Where(x => x.TradeType == "收益互换") on cash.TradeId equals trade.id
select cash;
//获取客户所有现存(抵押状态)抵押品信息
var clientProductList = db.clientcashincashout_product.Where(t =>
(t.Status == Clientcashincashout_productStatusEnum.抵押.ToString() && t.OptStatus == ClientCashInCashOut.已确认
|| t.Status == Clientcashincashout_productStatusEnum.赎回.ToString() && t.OptStatus != ClientCashInCashOut.已确认
|| t.Status == Clientcashincashout_productStatusEnum.赎回.ToString() && t.OptStatus == ClientCashInCashOut.已确认 && t.BackDate >= newValuedate)
&& clientIds.Contains(t.ClientId) && t.HappenDate < newValuedate).ToList();
var productUnderlyingIds = clientProductList.Select(t => t.UnderlyingId ?? 0).ToHashSet();
var umList = DataCacheProvider.GetUnderlyingDataSource();
var eodPriceProvider = EodPriceProviderFactory.Get(valueDate).GetPriceProvider(TradeCalcHelper.GetSettlementType());
var allTradeList = db.trade.Where(t => t.ValidState != "InValid" &&
t.TradeDate <= valueDate &&
clientIdList.Contains(t.ClientId) &&
ConsTrade.TradeStatusAfterConfirmed
.Contains(t.TradeStatus) &&
t.ParentTradeId == 0
).ToList();
var finishedTradeCash = from tc in db.trade_cash
join td in db.trade on tc.TradeId equals td.id
where (tc.ValueDate >= startDate && tc.ValueDate <= valueDate && tc.HappenedDate == null || tc.HappenedDate >= startDate && tc.HappenedDate <= valueDate)
&& tc.ValidState != ConsGlobal.InValid && !tc.IsDeleted
&& (tc.Action == ClientCashInCashOut.系统操作_平仓费 || tc.Action == ClientCashInCashOut.系统操作_行权费 || tc.Action == ClientCashInCashOut.系统操作_票息 || tc.Action == ClientCashInCashOut.系统操作_互换 || tc.Action == ClientCashInCashOut.人工操作_其他)
&& td.IsGroup != 1
select tc;
var finishedTradeNotionalList = finishedTradeCash.ToList();
var finishedTradeNotionalDic = finishedTradeNotionalList.GroupBy(tc => tc.TradeId).ToDictionary(g => g.Key,
g => g.Sum(tc =>
tc.Action == ClientCashInCashOut.系统操作_平仓费 ? (tc.UnwindNotional ?? 0) : tc.Notional));
//所有当日待结算的trade_cash记录(当日为应付日的冻结资金)
//var payDateTradeIds = db.trade.Where(t => t.TradeDate != valuedate && t.PremiumPayDate == valuedate).Select(t => t.id).ToList();
//var tradeCashList = db.trade_cash.Where(t => payDateTradeIds.Contains(t.TradeId ?? 0) && t.Status == TradeCashStatusEnum.冻结).ToList();
//获取当日所有执行的交易 交易日为当前交易日或者行权日为当前交易日
var positionTradeList = db.trade.Where(t => clientIds.Contains(t.ClientId))
.Where(t => t.TradeType != "场内期权")
.Where(t => t.ValidState != "InValid") //有效的交易
.Where(t => (t.TradeDate > lastSettletDate && t.TradeDate <= valueDate) &&
ConsTrade.NeedMarginTradeStatusList.Contains(t.TradeStatus)) //最后结算日到当日成交的交易
.Where(t => GlobalDicionary.SupportTradeTypes.Contains(t.TradeType));
//当日成交
var todayTradeList = positionTradeList.Where(t => t.TradeDate == valueDate).ToList();
var todayTradesAfterConfirmed = db.trade.Where(t => clientIds.Contains(t.ClientId))
.Where(t => t.TradeType != "场内期权")
.Where(t => t.ValidState != "InValid")
.Where(t => (t.TradeDate == valueDate) &&
ConsTrade.TradeStatusAfterConfirmed.Contains(t.TradeStatus))
.Where(t => (GlobalDicionary.SupportTradeTypes.Contains(t.TradeType) || t.TradeType == "结构化交易") && t.ParentTradeId == 0);
//positionTradeList.Where(t => t.TradeDate == valuedate || (unWindTradeStatus.Contains(t.TradeStatus) && t.UnWindDate==valuedate)).ToList();
var creditList = new List<CreditTable>();
//获取所有客户授信
creditList = db.credit.Where(t =>
clientIds.Contains(t.ClientId ?? 0) && t.ProcessStatus == "已审批" &&
(!t.CreditDeadLine.HasValue || t.CreditDeadLine >= valueDate) && (!t.CreditStartDate.HasValue || t.CreditStartDate <= valueDate)).ToList();
var clients = DataCacheProvider.GetClientDataSource().AsQueryable().ToList();
var parentexit = clients.Where(c => clientparentId.Contains(c.id)).ToList();
if (creditList.Count() == 0 && parentexit != null)
{
creditList = db.credit.Where(t =>
clientparentId.Contains(t.ClientId ?? 0) && t.ProcessStatus == "已审批" &&
(!t.CreditDeadLine.HasValue || t.CreditDeadLine >= valueDate) && (!t.CreditStartDate.HasValue || t.CreditStartDate <= valueDate)).ToList();
}
//获取所有资信等级
var creditRatingList = db2.credit_rating.Where(t => t.ValidState != "InValid").ToList();
//获取冻结资金信息
var clientFrozenFunds = new ClientFrozenFundsService(OptUserInfo.SystemUser).GetDatas(valueDate, clientIdList);
//预付金比率
var marginRation = systemDate.MarginRatio ?? 0.15;
//最大可提取预付金上限比率
var marginMaxRation = marginRation + 0.02;
DateTime? UpdateDate = null;
var ClientBanlanceList = new List<ClientSettleBalance>();
//客户盘中结算
clientList.ForEach(client =>
{
//当日应付冻结权利金
var FreezePremium = 0.0;
//冻结出金
var FrozenOutFund = 0.0;
//冻结抵押品赎回
var FrozenRedeemFunds = 0.0;
var OptionPremium = 0.0;
var OptionPremiumSwap = 0.0;
//平仓行权收益
var SettlementBalance = 0.0;
//平仓收益
var UnwindBalance = 0.0;
//行权收益
var ExerciseBalance = 0.0;
//互换收益
var SwapBalance = 0.0;
//当日应收冻结权利金
var ReceivablesPremium = 0.0;
//当日资金净出入
var NetFund = 0.0;
//其他收支
var OtherFund = 0.0;
//票息
var Coupon = 0.0;
//当日入金
var InFund = 0.0;
//当日出金
var OutFund = 0.0;
//其他收入
var InFundOther = 0.0;
//其他支出
var OutFundOther = 0.0;
//账户资金
var AmountFund = 0.0;
//前日账户资金
var LastDayRemainFund = 0.0;
//今日可用资金
var AvailableAmount = 0.0;
//授信额度
var lineOfCredit = 0.0;
//交易总数
var totalTradeCount = 0;
//交易笔数(当日成交)
var todayTradeCount = 0;
//交易总额
//var TradeTotalFund = 0.0;
//卖权交易数
var sellCount = 0;
//名义本金(卖出)
var SellNotionalPrincipal = 0.0;
//买权交易数
var buyCount = 0;
//名义本金(买入)
var BuyNotionalPrincipal = 0.0;
//名义本金总额
var totalNotionalPrincipal = 0.0;
//当日交易名义本金
var todayNotionalPrincipal = 0.0;
//持仓笔数
var PositionCount = 0;
//持仓市值
var PositionPv = 0.0;
var RoundedPositionPv = 0.0;
//空头持仓市值
var SellPv = 0.0;
//客户持仓交易预付金总和,客户买入为正,客户卖出为负
double PrepaymentAmount = 0.0;
//当日盈亏
var DaliyPnl = 0.0;
//持仓盈亏
var PositionPnl = 0.0;
var RoundedPositionPnl = 0.0;
//期权空头浮动盈利=∑max(期权空头持仓*(期权合约成本价-期权合约现价), 0) 从客户角度看的
var ClientSellPositionPnl = 0.0;
//抵押品
//应付预付金(要么为负要么为零)
//最新概念:负数代表客户应缴预付金,正数代表客户应收预付金
var PayableMargin = 0.0;
//互换占用预付金
var SwapPayableMargin = 0.0;
//互换容忍金额
var SwapUnMargin = 0.0;
//互换追保金额
var SwapMargin = 0d;
//双向预付金
var TwoSideMargin = 0.0;
//当日新增应付预付金
var TodayNewMargin = 0.0;
//潜在行权盈余
var PotentialSurpluses = 0.0;
//预付金余额
var MarginBalance = 0.0;
//追保金额
var Margin = 0.0;
//可取预付金
//可取预付金为预付金余额 - 应缴预付金(上浮2%)
var AdvisableMargin = 0.0;
//授信是否可用于期权费
var IsTradeCredit = true;
//实现盈亏
var WinLoss = 0.0;
//持仓期权费净额(客户角度卖出为负,买入为正)
var PositionPremiumNetCash = 0.0;
//权利金冻结:当日该客户所有持仓的卖出期权权利金
var SellTradePrice = 0.0;
// 期初持仓交易净额
var LastDayPositionPremiumNetCash = 0.0;
//可用名义本金规模
double? AvailableStockEqvNotional = null;
//当前互换流水费用
decimal curSwapFee = 0;
//获取客户授信
var credits = creditList?.Where(a => a.ClientId == client.id || a.ClientId == client.ParentId);
if (credits.Any())
{
lineOfCredit = credits.Sum(t => t.Credit ?? 0);
AvailableStockEqvNotional = creditList.Sum(O => O.StockEqvNotional) ?? 0;
}
else
{
lineOfCredit = 0.0;
AvailableStockEqvNotional = null;
}
var creditRatingId = 0;
var clientRatingQuery = from cr in db2.Client_Rating.Where(x => !x.IsDeleted && x.ProcessStatus == "已审批")
where cr.RatingStartDate <= valueDate && cr.RatingDeadLine >= valueDate && cr.ClientId == client.id
orderby cr.RatingDeadLine descending
orderby cr.ProcessOptDate descending
select cr.CreditRatingId;
if (clientRatingQuery.Any())
{
creditRatingId = clientRatingQuery.FirstOrDefault();
}
//资信等级授信额度
var creditRating = creditRatingList?.FirstOrDefault(a => a.id == creditRatingId);
var clientBanlance = clientBanlances.FirstOrDefault(a => a.ClientId == client.id);
AmountFund = clientBanlance == null ? 0.0 : clientBanlance.ToDayRemainFund ?? 0.0;
//上日资金余额
LastDayRemainFund = AmountFund;
//昨日抵押品总价值
var lastGuaranteesTotalAmount = clientBanlance == null
? 0.0
: clientBanlance.TodayRemianFundProduct ?? 0.0;
//资金净流入 + 权利金收支 + 期权费收支
var clientCashSwap = ClientCashSwapList.Where(a => a.ClientId == client.id).ToList();
if (clientCashSwap.Any())
{
if (clientCashSwap.Any(a => a.Direction == "应收" && cashSwapActions.Contains(a.Action)))
{
OptionPremiumSwap = clientCashSwap.Where(a => a.Direction == "应收" && cashSwapActions.Contains(a.Action)).Sum(a => a.Money ?? 0.0);
}
if (clientCashSwap.Any(a => a.Direction == "应收" && (a.Action == ClientCashInCashOut.系统操作_平仓费 || a.Action == ClientCashInCashOut.系统操作_互换)))
{
SwapBalance = clientCashSwap.Where(a => a.Direction == "应收" && (a.Action == ClientCashInCashOut.系统操作_平仓费 || a.Action == ClientCashInCashOut.系统操作_互换)).Sum(a => a.Money ?? 0.0);
}
}
curSwapFee = swapFlows.Where(x => x.ClientId == client.id).Sum(s => s.TradingFee);
OptionPremiumSwap += Convert.ToDouble(curSwapFee);
var clientCash = ClientCashList.Where(a => a.ClientId == client.id).ToList();
if (clientCash.Any())
{
if (clientCash.Any(a =>
a.Direction == "应收" && a.Action == ClientCashInCashOut.系统操作_期权费))
{
OptionPremium = clientCash
.Where(a => a.Direction == "应收" && a.Action == ClientCashInCashOut.系统操作_期权费)
.Sum(a => a.Money ?? 0.0);
}
if (clientCash.Any(a =>
a.Direction == "应收" &&
(a.Action == ClientCashInCashOut.系统操作_行权费 ||
a.Action == ClientCashInCashOut.系统操作_平仓费)))
{
var settlementCashList = clientCash.Where(a =>
a.Direction == "应收" &&
(a.Action == ClientCashInCashOut.系统操作_行权费 ||
a.Action == ClientCashInCashOut.系统操作_平仓费));
SettlementBalance = settlementCashList.Sum(a => a.Money ?? 0.0);
UnwindBalance = settlementCashList.Where(x => x.Action == ClientCashInCashOut.系统操作_平仓费).Sum(a => a.Money ?? 0.0);
ExerciseBalance = settlementCashList.Where(x => x.Action == ClientCashInCashOut.系统操作_行权费).Sum(a => a.Money ?? 0.0);
}
if (clientCash.Any(a => a.Action == ClientCashInCashOut.系统操作_票息))
{
Coupon = clientCash
.Where(a => a.Action == ClientCashInCashOut.系统操作_票息)
.Sum(a => a.Money ?? 0.0);
}
#region 计算实现盈亏
var todayFinishedTrades = allTradeList.Where(t => finishedTradeNotionalDic.Select(d => d.Key).Contains(t.id) && t.ClientId == client.id).ToList();
var todayFinishedTradeCash = from tc in finishedTradeCash
join td in db.trade on tc.TradeId equals td.id
where td.IsGroup != 1
group tc by td.ClientId into g
select new
{
ClientId = g.Key,
amountSum = g.Sum(n => n.Amount)
};
WinLoss = todayFinishedTrades.Sum(t => t.TradeType != "远期" ? (TradeCalcHelper.GetSign(t.BuySell) * (t.TradeSinglePrice ?? 0) * finishedTradeNotionalDic[t.id])
: (-(t.TradePrice ?? 0) * (finishedTradeNotionalDic[t.id] / (t.OriginalNotional ?? 0)))) //远期开仓总费用所占比重
- (todayFinishedTradeCash.FirstOrDefault(x => x.ClientId == client.id)?.amountSum ?? 0);
#endregion
if (clientCash.Any(a => a.Direction == "入金" || a.Direction == "出金"))
{
var inFunds = clientCash.Where(a => a.Direction == "入金").AsEnumerable().GroupBy(x => x.CurrencyCode).Select(x => new { x.Key, Money = x.Sum(y => y.Money ?? 0) }).ToList();
inFunds.ForEach(x =>
{
new EodCurrencyProvider(valueDate, false).TryGetCurrencyRate(x.Key, client.SettlementCurrency, out var rateObj);
if (rateObj == null)
{
throw new Exception($"{valueDate.ToString("yyyy-MM-dd")}未找到汇率:{x.Key}{client.SettlementCurrency}");
}
InFund += x.Money * rateObj.Rate;
});
var outFunds = clientCash.Where(a => a.Direction == "出金").AsEnumerable().GroupBy(x => x.CurrencyCode).Select(x => new { x.Key, Money = x.Sum(y => y.Money ?? 0) }).ToList();
outFunds.ForEach(x =>
{
new EodCurrencyProvider(valueDate, false).TryGetCurrencyRate(x.Key, client.SettlementCurrency, out var rateObj);
if (rateObj == null)
{
throw new Exception($"{valueDate.ToString("yyyy-MM-dd")}未找到汇率:{x.Key}{client.SettlementCurrency}");
}
OutFund += x.Money * rateObj.Rate;
});
NetFund = InFund - OutFund;
}
if (clientCash.Any(a => a.Direction == "其他收入" || a.Direction == "其他支出"))
{
var inFundOthers = clientCash.Where(a => a.Direction == "其他收入").AsEnumerable().GroupBy(x => x.CurrencyCode).Select(x => new { x.Key, Money = x.Sum(y => y.Money ?? 0) }).ToList();
inFundOthers.ForEach(x =>
{
new EodCurrencyProvider(valueDate, false).TryGetCurrencyRate(x.Key, client.SettlementCurrency, out var rateObj);
if (rateObj == null)
{
throw new Exception($"{valueDate.ToString("yyyy-MM-dd")}未找到汇率:{x.Key}{client.SettlementCurrency}");
}
InFundOther += x.Money * rateObj.Rate;
});
var outFundOthers = clientCash.Where(a => a.Direction == "其他支出").AsEnumerable().GroupBy(x => x.CurrencyCode).Select(x => new { x.Key, Money = x.Sum(y => y.Money ?? 0) }).ToList();
outFundOthers.ForEach(x =>
{
new EodCurrencyProvider(valueDate, false).TryGetCurrencyRate(x.Key, client.SettlementCurrency, out var rateObj);
if (rateObj == null)
{
throw new Exception($"{valueDate.ToString("yyyy-MM-dd")}未找到汇率:{x.Key}{client.SettlementCurrency}");
}
OutFundOther += x.Money * rateObj.Rate;
});
OtherFund = InFundOther + OutFundOther;
}
}
//抵押品资金价值
var tempClientProductList = clientProductList.Where(a => a.ClientId == client.id).ToList();
var GuaranteesTotalAmount = 0.0;
if (tempClientProductList.Any())
{
foreach (var t in tempClientProductList)
{
var um = umList.GetData(t.UnderlyingId ?? 0);
if (um != null)
{
if (!eodPriceProvider.TryGetPrice(um.UnderlyingCode, out var price_cp))
{
price_cp = umList.GetPrice(um.UnderlyingCode);
}
GuaranteesTotalAmount += (t.ProductAmount ?? 0) * (t.Rate ?? 0.0) * price_cp;
}
}
}
//持仓
//潜在行权盈余
PotentialSurpluses = 0.0;
var clientPositionList = positionList.Where(a =>
a.ClientId == client.id && ConsTrade.NeedMarginTradeStatusList.Contains(a.TradeStatus))
.ToList();
//持仓笔数
var clientPositionTrades = positionTrades.Where(t => t.ClientId == client.id &&
ConsTrade.NeedMarginTradeStatusList.Contains(t.TradeStatus));
PositionCount = clientPositionTrades.Count(t => t.ParentTradeId == 0) +
clientPositionTrades.Where(t => t.ParentTradeId > 0)
.AsEnumerable()
.GroupBy(t => t.ParentTradeId).Count();
//应付预付金
SellNotionalPrincipal = 0.0;
BuyNotionalPrincipal = 0.0;
totalNotionalPrincipal = 0.0;
UpdateDate = null;
if (PositionCount > 0)
{
UpdateDate = clientPositionList.Max(a => a.OptDate);
if (valuedate.PotentialSurplusCalcMode_ActualPv.Equals(systemDate
.PotentialSurplusCalcMode))
{
PotentialSurpluses =
clientPositionList.Where(x => x.TradeType != "结构化交易").Sum(a => a.ActualPv) * (-1); //潜在行权收益等于实值额
}
else
{
PotentialSurpluses =
Convert.ToDouble(clientPositionList.Where(x => x.TradeType != "结构化交易").Sum(a => a.Pv) * (-1)); //潜在行权收益等于实值额
}
PositionPv = Convert.ToDouble(clientPositionList.Where(x => x.TradeType != "结构化交易").Sum(a => a.Pv));
RoundedPositionPv = Convert.ToDouble(clientPositionList.Where(x => x.TradeType != "结构化交易").Sum(a => a.RoundedPv));
SellPv = Convert.ToDouble(clientPositionList.Where(x => x.TradeType != "结构化交易").Where(x => x.BuySell == "买入").Sum(a => a.Pv));
//客户持仓交易预付金总和,客户买入为正,客户卖出为负
PrepaymentAmount = positionTrades.Sum(x => x.StockEqvNotional * (x.trade_snowball?.PrepaymentRatio ?? 0) * (x.BuySell == "卖出" ? 1 : -1));
DaliyPnl = Convert.ToDouble(clientPositionList.Where(x => x.TradeType != "结构化交易").Sum(a =>
a.DailyPnL));
PositionPnl = clientPositionList.Where(x => x.TradeType != "结构化交易").Sum(a => a.PositionPnL);
RoundedPositionPnl = clientPositionList.Where(x => x.TradeType != "结构化交易").Sum(a => a.RoundedPositionPnl);
#region 期权空头浮动盈利=max(期权空头持仓*(期权合约成本价-期权合约现价), 0) 从客户角度看的, 结构化交易需要将两条腿的空头Pnl合计
var parentIds = clientPositionList.Where(x => x.TradeType == "结构化交易").Select(x => x.TradeId).ToList();
var parentPositionPnlList = from t in clientPositionList.Where(x => parentIds.Contains(x.ParentTradeId))
group t by new { t.ParentTradeId } into g
select new
{
parentTradeId = g.Key.ParentTradeId,
ClientSellPositionPnl = Math.Max(g.Sum(n => n.BuySell == "买入" ? -n.PositionPnL : 0), 0)
};
var parentPositionPnlTotal = parentPositionPnlList.Sum(x => x.ClientSellPositionPnl);
var singlePositionPnlTotal = clientPositionList.Where(x => x.TradeType != "结构化交易" && x.ParentTradeId == 0).Sum(n => n.BuySell == "买入" ? Math.Max(-n.PositionPnL, 0) : 0);
ClientSellPositionPnl = parentPositionPnlTotal + singlePositionPnlTotal;
#endregion
}
//获取tradespan 追保金额 = (当日资金余额 - 维持预付金) + 授信额度
var clientSpan = clientSpans.FirstOrDefault(t => t.ClientId == client.id);
PayableMargin = clientSpan == null || clientSpan.WorstCastClientPayable == null ? 0.0 : clientSpan.WorstCastClientPayable.Value;
TwoSideMargin = clientSpan == null || clientSpan.WorstCastClientPayable == null ? 0.0 : clientSpan.WorstCastClientPayable.Value;
SwapPayableMargin = clientSpan == null || clientSpan.SwapWorstCastClientPayable == null ? 0.0 : clientSpan.SwapWorstCastClientPayable.Value;
SwapUnMargin = clientSpan == null || clientSpan.SwapUnMargin == null ? 0.0 : clientSpan.SwapUnMargin.Value;
//存量交易持仓名义本金规模
AvailableStockEqvNotional -= allTradeList.Where(O => O.ClientId == client.id && ConsTrade.PositionTradeStatusList.Contains(O.TradeStatus) && O.ParentTradeId == 0).Sum(O => (double?)O.StockEqvNotional) ?? 0;
//交易数量
var clientAllTradeList = allTradeList.Where(t => t.ClientId == client.id).ToList();
if (clientAllTradeList.Count > 0)
{
//名义本金取 客户买入(交易员为卖出)的客户
SellNotionalPrincipal = clientAllTradeList.Sum(a =>
(a.OriginalStockEqvNotional > 0
? (a.OriginalStockEqvNotional ?? 0.0)
: ((a.SpotPrice ?? 0.0) * (a.OriginalNotional ?? 0))) *
("买入".Equals(a.BuySell) ? 1 : 0));
BuyNotionalPrincipal = clientAllTradeList.Sum(a =>
(a.OriginalStockEqvNotional > 0
? (a.OriginalStockEqvNotional ?? 0.0)
: ((a.SpotPrice ?? 0.0) * (a.OriginalNotional ?? 0))) *
("卖出".Equals(a.BuySell) ? 1 : 0));
totalNotionalPrincipal = SellNotionalPrincipal + BuyNotionalPrincipal;
buyCount = clientAllTradeList.Where(p => p.BuySell == "卖出").Count();
sellCount = clientAllTradeList.Where(p => p.BuySell == "买入").Count();
totalTradeCount = buyCount + sellCount;
}
//当日成交 新增交易
var todayClientTradeList = todayTradeList.Where(a => a.ClientId == client.id).ToList();
var addNewTradeIds = todayClientTradeList.Select(a => a.id).ToList();
if (addNewTradeIds.Count > 0 &&
clientPositionList.Where(x => x.ParentTradeId == 0).Any(a => addNewTradeIds.Contains(a.TradeId)))
{
//当日新增预付金
TodayNewMargin =
clientPositionList.Where(x => x.ParentTradeId == 0).Sum(a => (a.Margin) * (a.BuySell == "买入" ? -1 : 0));
}
var todayClientTradesAfterConfirmed = todayTradesAfterConfirmed.Where(a => a.ClientId == client.id).ToList();
//交易笔数
todayTradeCount = todayClientTradesAfterConfirmed.Count;
todayNotionalPrincipal = todayClientTradesAfterConfirmed.Sum(a =>
(a.OriginalStockEqvNotional > 0
? (a.OriginalStockEqvNotional ?? 0.0)
: ((a.SpotPrice ?? 0.0) * (a.OriginalNotional ?? 0))));
//应付冻结权利金
var clientFrozenFund = clientFrozenFunds[client.id];
FreezePremium = clientFrozenFund.FrozenPayableOptionMoney;
ReceivablesPremium = clientFrozenFund.FrozenReceivableOptionMoney;
FrozenOutFund = clientFrozenFund.OutFunds;
FrozenRedeemFunds = clientFrozenFund.RedeemFunds;
//冻结预付金(绝对值)
var FrozenMarginMoney = clientFrozenFund.FrozenMarginMoney;
//var tempTrades = positionTrade.Where(a => a.ClientId == client.id && trade.NeedMarginTradeStatusList.Contains(a.TradeStatus) && a.PremiumPayDate > valueDate).ToList();
//if (tempTrades.Any())
//{
// //应付冻结权利金
// if (tempTrades.Where(a => a.BuySell == "卖出").Any())
// {
// FreezePremium = tempTrades.Where(a => a.BuySell == "卖出").Sum(a => a.TradePrice ?? 0.0);
// }
// //应收冻结权利金
// if (tempTrades.Where(a => a.BuySell == "买入").Any())
// {
// ReceivablesPremium = tempTrades.Where(a => a.BuySell == "买入").Sum(a => a.TradePrice ?? 0.0);
// }
//}
//当前账号资金
AmountFund = AmountFund + NetFund + OtherFund + Coupon + SwapBalance + OptionPremium + OptionPremiumSwap + SettlementBalance;
//当日可用资金 账户总资金 - 应付冻结权利金 - 冻结出金 - 冻结抵押品赎回 + 应收冻结权利金 - 应付预付金 - 冻结预付金
AvailableAmount = AmountFund - FreezePremium - FrozenOutFund - FrozenRedeemFunds +
ReceivablesPremium + PayableMargin - FrozenMarginMoney;
//预付金余额
MarginBalance = AmountFund - FreezePremium - FrozenOutFund - FrozenRedeemFunds +
ReceivablesPremium + GuaranteesTotalAmount;
//判断潜在行权盈余是否计入预付金余额
if ((systemDate.IsPotentialSurplusUseMargin ?? 0) == 1)
{
MarginBalance += PotentialSurpluses;
AvailableAmount += PotentialSurpluses;
}
////追保金额
//Margin = Math.Max(PayableMargin - MarginBalance, 0);
// 除收益互换预付金资金占用后剩余资金
var marginBalanceSurplus = 0d;
//计算追保金额
//是否期权费授信
if ((client.IsTradeCredit ?? 0) == 1)
{
IsTradeCredit = true;
//授信是否可用于互换
if (client.creditCanApplySwap)
{
///期权费授信可以支付权利金 则预付金余额未0时 资金从 互换剔除互换容忍金额
Margin = Math.Min(MarginBalance + lineOfCredit + (PayableMargin - SwapUnMargin), 0);
}
else
{
//互换最大可用资金
marginBalanceSurplus = Math.Max(Math.Min(Math.Max(MarginBalance - OptionPremiumSwap + lineOfCredit + (PayableMargin - SwapPayableMargin), 0), Math.Max(MarginBalance - OptionPremiumSwap, 0)), 0);
//收益互换追保金额 剩余可支付互换资金 - (互换占用预付金 - 互换容忍预付金额度)
SwapMargin = Math.Min(marginBalanceSurplus + OptionPremiumSwap + (SwapPayableMargin - SwapUnMargin), 0);
//计算期权追保
Margin = Math.Min(MarginBalance - OptionPremiumSwap + lineOfCredit + (PayableMargin - SwapPayableMargin), 0) + SwapMargin;
}
}
else
{
IsTradeCredit = false;
//授信是否可用于互换
if (client.creditCanApplySwap)
{
//期权费授信不可以支付权力金时
Margin = Math.Min(Math.Max(MarginBalance, 0) + lineOfCredit + (PayableMargin - SwapUnMargin), 0) + Math.Min(MarginBalance, 0);
}
else
{
//互换最大可用资金
marginBalanceSurplus = Math.Max(Math.Min(Math.Max(Math.Max(MarginBalance - OptionPremiumSwap, 0) + lineOfCredit + (PayableMargin - SwapUnMargin), 0), Math.Max(MarginBalance - OptionPremiumSwap, 0)), 0);
//收益互换追保金额 剩余可支付互换资金 - (互换占用预付金 - 互换容忍预付金额度)
SwapMargin = Math.Min(marginBalanceSurplus + OptionPremiumSwap + (SwapPayableMargin - SwapUnMargin), 0) + Math.Min(marginBalanceSurplus + OptionPremiumSwap, 0);
//计算期权追保
Margin = Math.Min(Math.Max(MarginBalance - OptionPremiumSwap, 0) + lineOfCredit + (PayableMargin - SwapUnMargin), 0) + Math.Min(MarginBalance - OptionPremiumSwap, 0) + SwapMargin;
}
}
//可取预付金为预付金余额 - 应缴预付金(上浮 + 0.02)
AdvisableMargin = Math.Max(MarginBalance + PayableMargin * marginMaxRation / marginRation, 0);
LastDayPositionPremiumNetCash = clientBanlance == null ? 0.0 : clientBanlance.PositionPremiumNetCash ?? 0.0;
PositionPremiumNetCash = clientPositionList.Sum(t =>
t.Cost * (-TradeCalcHelper.GetSign(t.BuySell)));
SellTradePrice = clientPositionList.Where(x => x.BuySell == "买入").Sum(t => (t.Cost));
#region 新交易权利金, 新交易预付金,新交易初保,额外追保,总追保金额
var todayNewClientPostionList = clientPositionList
.Where(a => addNewTradeIds.Contains(a.TradeId)).ToList();
#endregion
ClientBanlanceList.Add(new ClientSettleBalance
{
ValueDate = valueDate,
ClientId = client.id,
FreezePremium = FreezePremium,
FrozenOutFund = FrozenOutFund,
FrozenRedeemFunds = FrozenRedeemFunds,
ReceivablesPremium = ReceivablesPremium,
NetFund = NetFund,
OtherFund = OtherFund,
AmountFund = AmountFund,
LastDayRemainFund = LastDayRemainFund,
LastDayRemainFundWithProduct = LastDayRemainFund + lastGuaranteesTotalAmount,
AvailableAmount = AvailableAmount,
CreditRating = creditRating == null ? "" : creditRating.CreditName,
TotalCredit = lineOfCredit,
//CreditUsed = lineOfCredit > 0 ? Math.Max(-AvailableAmount / lineOfCredit, 0.0) : 0.0,
TradeCount = todayTradeCount,
SellNotionalPrincipal = SellNotionalPrincipal,
BuyNotionalPrincipal = BuyNotionalPrincipal,
PositionCount = PositionCount,
PayableMargin = PayableMargin,
TwoSideMargin = TwoSideMargin,
PotentialSurpluses = PotentialSurpluses,
MarginBalance = MarginBalance,
Margin = Margin,
AdvisableMargin = AdvisableMargin,
UpdateDate = UpdateDate,
IsTradeCredit = IsTradeCredit,
OptionPremium = OptionPremium,
OptionPremiumSwap = OptionPremiumSwap,
SwapPayableMargin = SwapPayableMargin,
SwapUnMargin = SwapUnMargin,
SettlementBalance = SettlementBalance,
UnwindBalance = UnwindBalance,
ExerciseBalance = ExerciseBalance,
SwapBalance = SwapBalance,
Coupon = Coupon,
TodayNewMargin = TodayNewMargin,
GuaranteesTotalAmount = GuaranteesTotalAmount,
PositionPv = PositionPv * (-1), //客户方向取反
RoundedPositionPv = RoundedPositionPv * (-1),
SellPv = SellPv * (-1),
PrepaymentAmount = PrepaymentAmount,
DaliyPnl = DaliyPnl * (-1),
PositionPnl = PositionPnl * (-1),
RoundedPositionPnl = RoundedPositionPnl * (-1),
ClientSellPositionPnl = ClientSellPositionPnl,
LastGuaranteesTotalAmount = lastGuaranteesTotalAmount,
CashInCashOutProductChange = GuaranteesTotalAmount - lastGuaranteesTotalAmount,
TotalTradeCount = totalTradeCount,
SellCount = sellCount,
BuyCount = buyCount,
TotalNotionalPrincipal = totalNotionalPrincipal,
TodayNotionalPrincipal = todayNotionalPrincipal,
PositionPremiumNetCash = PositionPremiumNetCash,
SellTradePrice = SellTradePrice,
LastDayPositionPremiumNetCash = LastDayPositionPremiumNetCash,
WinLoss = WinLoss,
AvailableStockEqvNotional = AvailableStockEqvNotional ?? 0,
});
});
return ClientBanlanceList;
}
}
public static bool TradeCanBeConfirm(int clientId, trade trade, out string errorMsg)
{
errorMsg = "";
if (trade.TradeType == "现金流交易" || (trade.TradeType == "结构化交易" && trade.UnderlyingCode == null))
{
return true;
}
var clientBalances = GetRealTimeClientBanlance(new List<int> { clientId });
if (clientBalances == null || clientBalances.Count <= 0)
{
errorMsg = "客户实时资金错误!";
return false;
}
if (trade.Warning)
{
new TradeDalService(OptUserInfo.SystemUser).RollbackToBeforeSettle(trade, valuedateBLL.ValueDate);
}
if (trade.IsOption() || trade.TradeType == "结构化交易" || trade.TradeType == "自定义交易")
{
//交易为买入 即:客户为卖出
if (EnumTradeBuySell.Buy.Equals(trade.BuySell))
{
var clientBalance = clientBalances[0];
using (var db = new YLContext())
{
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingId);
if (underlying == null)
{
errorMsg = "未找到标的信息";
return false;
}
if (trade.ExerciseDate.Value.Date >= valuedateBLL.ValueDate.Date)
{
var tradePrice = trade.TradePrice * (-TradeCalcHelper.GetSign(trade.BuySell));
var margin = trade.InitialMargin ?? 0;
var endMoney = margin + tradePrice;
var AvailableAmount = Math.Max(clientBalance.AvailableAmount + clientBalance.TotalCredit, 0);
if (AvailableAmount < endMoney)
{
errorMsg = $"当前交易应付预付金:{margin:#,##0.000},应付成交金额:{tradePrice:#,##0.000},总应付资金:{endMoney:#,##0.000}。当前剩余资金:{clientBalance.AmountFund:F3},冻结资金:{clientBalance.AllFreezeBalance():F3},抵押品价值:{clientBalance.GuaranteesTotalAmount:F3},授信额度:{clientBalance.TotalCredit:F3},可用总额度:{AvailableAmount:F3}。不足以支付上述金额。";
return false;
}
}
return true;
}
}
else//交易为卖出 即:客户为买入
{
var clientBalance = clientBalances[0];
var tradePrice = trade.TradePrice;
var AvailableAmount = clientBalance.AvailablePremium();
var endMoney = tradePrice;
if (AvailableAmount >= tradePrice)
{
return true;
}
else
{
errorMsg = $"当前交易应付预付金:{0:#,##0.000},应付成交金额:{tradePrice:#,##0.000},总应付资金:{endMoney:#,##0.000}。当前剩余资金:{clientBalance.AmountFund:F3},冻结资金:{clientBalance.AllFreezeBalance():F3},抵押品价值:{clientBalance.GuaranteesTotalAmount:F3},授信额度:{clientBalance.TotalCredit:F3},可用总额度:{AvailableAmount:F3}。不足以支付上述金额。";
return false;
}
}
}
else if (trade.TradeType == "收益互换")
{
var clientBalance = clientBalances[0];
using (var db = new YLContext())
{
var tradePrice = trade.TradePrice * (-TradeCalcHelper.GetSign(trade.BuySell));
var AvailableAmount = clientBalance.AvailablePremium();
if (AvailableAmount < tradePrice && tradePrice > 0)
{
var endMoney = tradePrice;
errorMsg = $"当前交易应付预付金:{0:#,##0.000},应付成交金额:{tradePrice:#,##0.000},总应付资金:{endMoney:#,##0.000}。当前剩余资金:{clientBalance.AmountFund:F3},冻结资金:{clientBalance.AllFreezeBalance():F3},抵押品价值:{clientBalance.GuaranteesTotalAmount:F3},授信额度:{clientBalance.TotalCredit:F3},可用总额度:{AvailableAmount:F3}。不足以支付上述金额。";
return false;
}
else
{
if (trade.StructureType != "多空组合")
{
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingId);
if (underlying == null)
{
errorMsg = "未找到标的信息";
return false;
}
}
if (trade.ExerciseDate.Value.Date >= valuedateBLL.ValueDate.Date)
{
var margin = trade.InitialMargin ?? 0;
var endMoney = margin + tradePrice;
AvailableAmount = Math.Max(clientBalance.AvailableAmount + clientBalance.TotalCredit, 0);
if (AvailableAmount < margin + tradePrice)
{
errorMsg = $"当前交易应付预付金:{trade.InitialMargin ?? 0:#,##0.000},应付成交金额:{tradePrice:#,##0.000},总应付资金:{endMoney:#,##0.000}。当前剩余资金:{clientBalance.AmountFund:F3},冻结资金:{clientBalance.AllFreezeBalance():F3},抵押品价值:{clientBalance.GuaranteesTotalAmount:F3},授信额度:{clientBalance.TotalCredit:F3},可用总额度:{AvailableAmount:F3}。不足以支付上述金额,交易费用:{tradePrice ?? 0:F3}";
return false;
}
}
return true;
}
}
}
else if (trade.TradeType == "远期")
{
using (var db = new YLContext())
{
var forwardTrade = db.trade_forward.FirstOrDefault(x => x.TradeId == trade.id);
if (forwardTrade != null)
{
//远期验资,验证客户余额>= 开仓总费用
var clientBalance = clientBalances[0];
var totalOpenCommission = trade.TradePrice ?? 0;
var AvailableAmount = clientBalance.AvailablePremium();
if (AvailableAmount >= totalOpenCommission || totalOpenCommission < 0)
{
return true;
}
else
{
errorMsg = $"当前剩余资金:{clientBalance.AmountFund:F3},冻结资金:{clientBalance.AllFreezeBalance():F3},应付预付金:{clientBalance.PayableMargin:F3},抵押品价值:{clientBalance.GuaranteesTotalAmount:F3},授信额度:{clientBalance.TotalCredit:F3},可用总额度:{AvailableAmount:F3}。不足以支付开仓总金额:{totalOpenCommission:F3}";
return false;
}
}
else
{
errorMsg = "客户远期交易数据未找到!";
return false;
}
}
}
else
{
errorMsg = "非期权交易,无需检查!";
return false;
}
}
/// <summary>
/// 实时计算收益互换实时持仓
/// </summary>
/// <param name="td"></param>
/// <returns></returns>
public static intraday_trade_position RealTimeSwapCalc(trade td, YLContext db, List<swap_flow> swapFlows)
{
intraday_trade_position posi = new intraday_trade_position();
var position = db.swap_position.FirstOrDefault(x => x.SwapTradeId == td.id && x.PosiDirection > 0 && x.IsInitial);
if (position == null)
{
return null;
}
var swapFlowItems = swapFlows.Where(x => x.ClientId == td.ClientId && x.UnderlyingCode == position.UnderlyingCode);
return posi;
}
public static ClientBalanceForTrsResponse GetClientBalance(int clientId)
{
if (_yLCache!=null)
{
return _yLCache.StringGet<ClientBalanceForTrsResponse>("ClientBalance:" + clientId);
}
return null;
}
}
}