345 lines
15 KiB
C#
345 lines
15 KiB
C#
using BaseOUDAL;
|
|
using MathNet.Numerics;
|
|
using System.Linq.Dynamic.Core;
|
|
using YLErp.Commons;
|
|
using YLErp.Model;
|
|
using YLErp.Modules.DataProviderModule;
|
|
|
|
namespace YLErp.Modules.SuperviseReportModule.ChangJiangReport.Service
|
|
{
|
|
public class SuperviseReportPositionService : YLBaseService
|
|
{
|
|
public SuperviseReportPositionService(OptUserInfo userInfo) : base(userInfo)
|
|
{
|
|
}
|
|
|
|
public SuperviseReportPositionService(YLBaseService baseService) : base(baseService)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// 从数据库中查询场外业务持仓信息
|
|
/// <para>长江数据采集用</para>
|
|
/// </summary>
|
|
public SearchListResult<SupervisePositionDbModel> SearchSuperviseReportList(SuperviseReportReq req)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(req.sidx)) { req.sidx = nameof(SupervisePositionDbModel.id); }
|
|
|
|
var query = from db in DbContext.SuperviseReportPosition
|
|
where db.ValueDate == req.ValueDate
|
|
select db;
|
|
switch (req.DataSource)
|
|
{
|
|
case "不为零":
|
|
query = query.Where(O => !(O.DeltaCash == 0 && O.GammaCash == 0 && O.HoldCash == 0 && O.PositionPnl == 0 && O.StockEqvNotional == 0 && O.TradePrice == 0));
|
|
break;
|
|
case "全量":
|
|
default:
|
|
break;
|
|
}
|
|
return query.ToSearchList(req);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存场外业务持仓信息到数据库
|
|
/// <para>长江数据采集用</para>
|
|
/// </summary>
|
|
/// <param name="valueDate">数据日期</param>
|
|
public int SaveReportData(DateTime valueDate, string exposureDataSourceType = null, bool clearExsitings = false)
|
|
{
|
|
var models = DbContext.SuperviseReportPosition.Where(a => a.ValueDate == valueDate);
|
|
|
|
if (models.Any())
|
|
{
|
|
if (!clearExsitings)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
SupervisePositionDbModel t;
|
|
DbContext.BulkDelete<SupervisePositionDbModel>($"{nameof(t.ValueDate)}='{valueDate:yyyy-MM-dd}'");
|
|
}
|
|
|
|
IQueryable<EodTradeRisk> tRisk;
|
|
|
|
var useClosePrice = true;
|
|
|
|
switch (exposureDataSourceType)
|
|
{
|
|
default:
|
|
tRisk = DbContext.eod_trade_risk_hedgevol;
|
|
break;
|
|
case "收盘价+持仓波动率":
|
|
tRisk = DbContext.eod_trade_risk;
|
|
break;
|
|
case "结算价+持仓波动率":
|
|
useClosePrice = false;
|
|
tRisk = DbContext.eod_trade_risk_s;
|
|
break;
|
|
case "结算价+对冲波动率":
|
|
useClosePrice = false;
|
|
tRisk = DbContext.eod_trade_risk_hedgevol_s;
|
|
break;
|
|
}
|
|
|
|
//长江-依文文2022-04-20 提出需要排除新基差簿记的交易;
|
|
var bookIds = DbContext.assetunit.Where(O => O.Name.Contains("新基差")).Select(O => O.id);
|
|
|
|
var query = from position in DbContext.eod_trade_position
|
|
join risk in tRisk
|
|
on new
|
|
{
|
|
position.ValueDate,
|
|
HedgeUniqueCode = position.HedgeUniqueCode + "_" + position.TradeId,
|
|
} equals new
|
|
{
|
|
risk.ValueDate,
|
|
HedgeUniqueCode = risk.HedgeUniqueCode + "_" + risk.TradeId,
|
|
} into tempRisk
|
|
from risk in tempRisk.DefaultIfEmpty()
|
|
join trade in DbContext.eod_trade
|
|
on new
|
|
{
|
|
position.ValueDate,
|
|
position.TradeId
|
|
} equals new
|
|
{
|
|
trade.ValueDate,
|
|
trade.TradeId
|
|
} into tempTrade
|
|
from trade in tempTrade.DefaultIfEmpty()
|
|
where position.ValueDate == valueDate && position.TradeType != "现金流交易" && !bookIds.Contains(position.BookId)
|
|
select new
|
|
{
|
|
risk,
|
|
position.Pv,
|
|
position.Cost,
|
|
position.Amount,
|
|
position.BuySell,
|
|
position.TradeType,
|
|
position.PositionPnL,
|
|
position.PositionType,
|
|
position.UnderlyingCode,
|
|
position.ExchangeOptionCode,
|
|
eodTrade = trade,
|
|
};
|
|
|
|
var objs = new List<SupervisePositionDbModel>();
|
|
var positionTypes = new List<string>() { "卖出", "多头平仓", "空头开仓" };
|
|
var tradeTypes = new List<string>() { "远期", "收益互换" };
|
|
var priceProvider = new EodPriceProvider(valueDate, isDiviendPrice: false);
|
|
foreach (var item in query)
|
|
{
|
|
var trade = item.eodTrade?.trade;
|
|
var variety = DataCacheProvider.GetVariety(item.UnderlyingCode);
|
|
var obj = new SupervisePositionDbModel();
|
|
obj.ValueDate = valueDate;
|
|
if (trade == null || ConsTrade.TradeTypesForHedge.Contains(trade.TradeType))
|
|
{
|
|
obj.Trade_Number = "";
|
|
priceProvider.TryGetEodPrice(item.UnderlyingCode, out var eodPrice);
|
|
var price = eodPrice?.GetPrice(SettlementTypeEnum.SettlePrice) ?? 0;
|
|
obj.StockEqvNotional = Math.Abs(price * item.Amount);
|
|
obj.BusinessType = "场外期权成交自主对冲";
|
|
obj.TradeType = item.TradeType;
|
|
obj.ClientName = variety.TradingMarket;
|
|
obj.DeltaCash = item.risk?.DeltaCash ?? 0;
|
|
if (item.TradeType == "场内期权")
|
|
{
|
|
var exchangeOptionInfo = DataCacheProvider.GetExchangeListOptionDataSource().GetData(item.ExchangeOptionCode);//ExchangeOptionCode场内标的
|
|
obj.StockEqvNotional = Math.Abs(exchangeOptionInfo.Strike * item.Amount);
|
|
if (positionTypes.Contains(item.BuySell))
|
|
{
|
|
obj.BuySell = "卖出";
|
|
obj.HoldCash = obj.StockEqvNotional * variety.Margin ?? 0;
|
|
}
|
|
else
|
|
{
|
|
obj.BuySell = "买入";
|
|
obj.HoldCash = 0;
|
|
}
|
|
obj.TradePrice = -item.Cost;
|
|
}
|
|
else
|
|
{
|
|
obj.HoldCash = obj.StockEqvNotional * variety.Margin ?? 0;
|
|
obj.Amount = Math.Abs(item.Amount);
|
|
|
|
if (useClosePrice)
|
|
{
|
|
price = eodPrice?.GetPrice(SettlementTypeEnum.ClosePrice) ?? 0; ;
|
|
}
|
|
|
|
obj.DeltaCash = item.Amount * price;
|
|
|
|
if (item.PositionType == "long")
|
|
{
|
|
obj.BuySell = "买入";
|
|
}
|
|
else
|
|
{
|
|
obj.BuySell = "卖出";
|
|
}
|
|
obj.isFutures = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!ConsTrade.LiveTradeStatusList.Contains(trade.TradeStatus))
|
|
{
|
|
continue;
|
|
}
|
|
var type = (trade.Comments?.Trim().FirstOrDefault() ?? '0').ToString();
|
|
//1.套利和通道业务
|
|
//2.场外期权成交自主对冲
|
|
//3.商业类和政策类保险 + 期货
|
|
//4.交易所项目;
|
|
//5.融资业务
|
|
switch (type)
|
|
{
|
|
case "1":
|
|
obj.BusinessType = "套利业务";
|
|
break;
|
|
case "3":
|
|
obj.BusinessType = "商业类和政策类保险 + 期货";
|
|
break;
|
|
case "4":
|
|
obj.BusinessType = "交易所项目";
|
|
break;
|
|
case "5":
|
|
obj.BusinessType = "其他业务";
|
|
break;
|
|
case "2":
|
|
default:
|
|
obj.BusinessType = "场外期权成交自主对冲";
|
|
break;
|
|
}
|
|
obj.Trade_Number = trade.TradeNumber;
|
|
obj.ClientName = trade.ClientName;
|
|
obj.BuySell = trade.BuySell;
|
|
if (tradeTypes.Contains(trade.TradeType))
|
|
{
|
|
obj.TradeType = trade.StructureType ?? trade.TradeType;
|
|
}
|
|
else
|
|
{
|
|
obj.TradeType = trade.ExerciseModeCn + trade.OptionType;
|
|
}
|
|
var strike = (trade.IsMoneynessOptionData ? (trade.Strike * trade.SpotPrice) : trade.Strike) ?? 0;
|
|
if (trade.TradeType == "收益互换")
|
|
{
|
|
strike = trade.SpotPrice ?? 0;
|
|
}
|
|
obj.StockEqvNotional = strike * trade.Notional;
|
|
obj.TradeId = trade.id;
|
|
obj.TradePrice = (trade.TradePrice * (trade.StockEqvNotional / trade.OriginalStockEqvNotional) * (trade.BuySell == "买入" ? -1 : 1)) ?? 0;
|
|
obj.DeltaCash = item.risk?.DeltaCash ?? 0;
|
|
}
|
|
obj.Project = $"{variety.VarietyName}{obj.BusinessType}";
|
|
obj.VarietyCode = variety.VarietyCode;
|
|
obj.UnderlyingCode = item.UnderlyingCode;
|
|
obj.PositionPnl = item.PositionPnL;
|
|
obj.GammaCash = item.risk?.GammaCash ?? 0;
|
|
obj.ExchangeOptionCode = item.ExchangeOptionCode;
|
|
objs.Add(obj);
|
|
}
|
|
var listGroup = objs.GroupBy(O => $"{O.Project}_{O.ClientName}_{O.BuySell}_{O.TradeType}_{O.ExchangeOptionCode ?? O.UnderlyingCode}_{O.TradeId}")
|
|
.ToDictionary(K => K.Key);
|
|
var futureAmountInfos = new Dictionary<string, SupervisePositionDbModel>();
|
|
var dict =
|
|
objs.GroupBy(O => $"{O.Project}_{O.ClientName}_{O.BuySell}_{O.TradeType}_{O.ExchangeOptionCode ?? O.UnderlyingCode}_{O.TradeId}")
|
|
.ToDictionary(K => K.Key,
|
|
V =>
|
|
{
|
|
var obj = V.First();
|
|
var i = 0;
|
|
V.ToList().ForEach(O =>
|
|
{
|
|
i++;
|
|
if (i == 1)
|
|
{ return; }
|
|
obj.StockEqvNotional += O.StockEqvNotional;
|
|
obj.TradePrice += O.TradePrice;
|
|
obj.PositionPnl += O.PositionPnl;
|
|
if (O.isFutures)
|
|
{
|
|
obj.HoldCash += O.HoldCash;
|
|
obj.Amount += O.Amount;
|
|
}
|
|
else if (O.TradeType == "场内期权")
|
|
{
|
|
obj.HoldCash += O.HoldCash;
|
|
}
|
|
obj.DeltaCash += O.DeltaCash;
|
|
obj.GammaCash += O.GammaCash;
|
|
});
|
|
if (obj.isFutures)
|
|
{
|
|
if (!futureAmountInfos.ContainsKey(obj.UnderlyingCode))
|
|
{
|
|
futureAmountInfos[obj.UnderlyingCode] = obj;
|
|
return obj;
|
|
}
|
|
if (futureAmountInfos[obj.UnderlyingCode].Amount > obj.Amount)
|
|
{
|
|
obj.HoldCash = 0;
|
|
}
|
|
else
|
|
{
|
|
futureAmountInfos[obj.UnderlyingCode].HoldCash = 0;
|
|
}
|
|
}
|
|
obj.HoldCash = OtcFormatHelper.FormatValue(obj.HoldCash, 6);
|
|
obj.TradePrice = OtcFormatHelper.FormatValue(obj.TradePrice, 6);
|
|
obj.StockEqvNotional = OtcFormatHelper.FormatValue(obj.StockEqvNotional, 6);
|
|
obj.PositionPnl = OtcFormatHelper.FormatValue(obj.PositionPnl, 6);
|
|
obj.DeltaCash = OtcFormatHelper.FormatValue(obj.DeltaCash, 6);
|
|
obj.GammaCash = OtcFormatHelper.FormatValue(obj.GammaCash, 6);
|
|
return obj;
|
|
});
|
|
var list = dict.Values.OrderBy(O => $"{O.Project}_{O.ClientName}_{O.BuySell}_{O.TradeType}_{O.ExchangeOptionCode ?? O.UnderlyingCode}_{O.TradeId}").ToList();
|
|
|
|
if (list.Any())
|
|
{
|
|
DbContext.SuperviseReportPosition.AddRange(list);
|
|
return DbContext.SaveChanges();
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
public void BatchSupervisePosition(List<int> Ids, DateTime ValueDate, bool IsAll, string Type)
|
|
{
|
|
var predicate = PredicateBuilder.True<SupervisePositionDbModel>().And(a => a.ValueDate == ValueDate);
|
|
if (!IsAll)//非全选
|
|
{
|
|
predicate = predicate.And(a => Ids.Contains(a.id));
|
|
}
|
|
using (var db = DbContextFactory.GetYLDbContext())
|
|
{
|
|
var clietnCashs = db.SuperviseReportPosition.Where(predicate);
|
|
if (clietnCashs.Any())
|
|
{
|
|
if (Type == "update")//更新确认状态
|
|
{
|
|
foreach (var item in clietnCashs)
|
|
{
|
|
item.Status = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
db.SuperviseReportPosition.RemoveRange(clietnCashs);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new ServiceException("没有数据进行批量操作");
|
|
}
|
|
db.SaveChanges();
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|