using Microsoft.EntityFrameworkCore.Storage;
using YLErp.BLL;
using YLErp.BLL.MarginCalculation;
using YLErp.Configuration;
using YLErp.CustomizedBizLogic;
using YLErp.DBModels.Consts;
using YLErp.DBModels.Helpers;
using YLErp.Enums;
using YLErp.Helpers;
using YLErp.Model.Enum;
using YLErp.Modules.SalesModule;
using YLErp.Modules.TagModule;
using YLErp.Modules.TradeModule.DealModule;
namespace YLErp.Modules.TradeModule.OrderModule
{
///
/// 交易保存服务
///
public class TradeSaveService : TradeServiceBase
{
TradeSourceEnum _source;
public TradeSaveService(OptUserInfo userInfo) : base(userInfo)
{
}
public TradeSaveService(YLBaseService baseService) : base(baseService)
{
}
///
///
///
public trade SaveTrade(trade req, TradeSourceEnum source, IDbContextTransaction trans = null)
{
if (req is null)
{
throw new ArgumentNullException(nameof(req));
}
_source = source;
var noTrans = trans == null;
try
{
if (noTrans)
{
trans = DbContext.Database.BeginTransaction();
}
//交易保存处理
var preHandler = new TradeSavePreHandler(this);
req = preHandler.Prepare(req, _source);
var dbTrade = preHandler.isAddNew
? InnerSaveNewTrade(req, preHandler.TradeNumberGenerated)
: (req.IsGroup == 1 && req.TradeType == "收益互换" ? InnerSaveEditSwapGroupTrade(req) : InnerSaveEditTrade(req, out var changeConfirmStatus));
//销售佣金数据处理
if (dbTrade.TradeType == "结构化交易")
{
foreach (var subTrade in req.SubTrades)
{
if (subTrade.SalesCommission != null)
{
subTrade.SalesCommission.ClientId = subTrade.ClientId;
if (PS.Config.ErpElement.SalesCommissionCalculation == "默认" || PS.Config.ErpElement.SalesCommissionCalculation == "" || PS.Config.ErpElement.SalesCommissionCalculation == null)
{
new SalesCommissionDataService(this).SaveTradeCommission(subTrade.id, subTrade.SalesCommission, false);
}
else if (PS.Config.ErpElement.SalesCommissionCalculation == "公式1")
{
if (req.SalesCommission?.SalesIds != null && req.SalesCommission.SalesIds.Any())
{
new SalesCommissionDetailDataService(this).SaveTradeCommissionDetail(subTrade.id, subTrade.SalesCommission.ClientId, subTrade.SalesCommission.Commission, subTrade.SalesCommission.CommissionFixed, subTrade.SalesCommission.SalesIds, false);
}
else
{
new SalesCommissionDetailDataService(this).RemoveTradeCommissionDetail(subTrade.id);
}
}
else { } //todo
}
if (dbTrade.StructureType == "折价" && PS.Config.Is国泰君安)
{
saveZheJiaTradeMarginTemplate(subTrade, dbTrade);
}
}
}
else
{
if (req.SalesCommission != null)
{
req.SalesCommission.ClientId = dbTrade.ClientId;
}
if (PS.Config.ErpElement.SalesCommissionCalculation == "默认" || PS.Config.ErpElement.SalesCommissionCalculation == "" || PS.Config.ErpElement.SalesCommissionCalculation == null)
{
new SalesCommissionDataService(this).SaveTradeCommission(dbTrade.id, req.SalesCommission, false);
}
else if (PS.Config.ErpElement.SalesCommissionCalculation == "公式1")
{
if (req.SalesCommission?.SalesIds != null && req.SalesCommission.SalesIds.Any())
{
new SalesCommissionDetailDataService(this).SaveTradeCommissionDetail(dbTrade.id, req.SalesCommission.ClientId, req.SalesCommission.Commission, req.SalesCommission.CommissionFixed, req.SalesCommission.SalesIds, false);
}
else
{
new SalesCommissionDetailDataService(this).RemoveTradeCommissionDetail(dbTrade.id);
}
}
else { } //todo
}
//执行事务
if (noTrans)
{
trans.Commit();
}
return dbTrade;
}
finally
{
if (noTrans)
{
trans?.Dispose();
}
}
}
public trade SaveGroupTrade(OtcOptionTradeFull req, int[] tradeIds)
{
if (req.id > 0 && ConsTrade.TradeStatusAfterConfirmed.Contains(req.TradeStatus))
{
new TradeBackService(UserInfo).BackGroup(req.id, true, TradeBackActionEnum.EditMaturityDate);
}
var countRatio = (DataCacheProvider.GetUnderlyingDataSource().GetData(req.UnderlyingId)?.CountRatio) ?? 1;
if (req.IsUsePremiumRate == true)
{
req.Notional = req.SpotPrice != null && req.SpotPrice != 0 ? req.StockEqvNotional / req.SpotPrice.Value : 0;
req.TradeAmount = req.Notional / countRatio;
}
else
{
req.Notional = req.TradeAmount * countRatio;
req.StockEqvNotional = req.Notional * req.SpotPrice ?? 0;
}
req.PremiumRate = req.StockEqvNotional != 0 ? (req.TradePrice ?? 0) / req.StockEqvNotional : 0;
req.TradeSinglePrice = req.Notional != 0 ? (req.TradePrice ?? 0) / req.Notional : 0;
var dbTrade = TradeConverter.ConvertOptionTrade(req);
dbTrade.StartDate = dbTrade.TradeDate;
dbTrade.SettlementDate = dbTrade.ExerciseDate;
dbTrade.OriginalNotional = dbTrade.Notional;
dbTrade.OriginalStockEqvNotional = dbTrade.StockEqvNotional;
dbTrade.StockEqvNotionalMax = dbTrade.StockEqvNotional;
dbTrade.StockEqvNotionalReal = TradeHelper.GetStockEqvNotionalReal(dbTrade.StockEqvNotional, dbTrade.ParticipationRate, dbTrade.AnnualizeFactor);
if (req.id > 0)
{
var trade = DbContext.trade.AsNoTracking().FirstOrDefault(x => x.id == req.id);
if (trade == null)
{
throw new ServiceException($"该交易不存在");
}
var isDiffStructureType = trade.StructureType != req.StructureType;
trade.SpotPrice = req.SpotPrice;
trade.ExerciseDate = dbTrade.ExerciseDate;
trade.SettlementDate = dbTrade.ExerciseDate;
trade.BuySell = dbTrade.BuySell;
trade.IsUsePremiumRate = dbTrade.IsUsePremiumRate;
trade.TradeAmount = dbTrade.TradeAmount;
trade.Notional = dbTrade.Notional;
trade.OriginalNotional = dbTrade.OriginalNotional;
trade.StockEqvNotional = dbTrade.StockEqvNotional;
trade.OriginalStockEqvNotional = dbTrade.OriginalStockEqvNotional;
trade.StockEqvNotionalReal = dbTrade.StockEqvNotionalReal;
trade.TradeSinglePrice = dbTrade.TradeSinglePrice;
trade.PremiumRate = dbTrade.PremiumRate;
trade.TradePrice = dbTrade.TradePrice;
trade.IsMoneynessOption = dbTrade.IsMoneynessOption;
trade.StructureType = dbTrade.StructureType;
trade.Strike = dbTrade.Strike;
trade.AssetId = dbTrade.AssetId;
trade.AssetBookName = dbTrade.AssetBookName;
trade.TraderId = dbTrade.TraderId;
trade.TraderName = dbTrade.TraderName;
trade.Comments = dbTrade.Comments;
trade.StockEqvNotionalMax = dbTrade.StockEqvNotionalMax;
if (trade.StructureType == "气囊结构")
{
trade.ExtendInfo = null;
trade.trade_airbag = dbTrade.trade_airbag;
trade.OptionType = dbTrade.OptionType;
}
else
{
trade.ExtendInfo = dbTrade.ExtendInfo;
}
if (DbContext.trade.Any(n => n.TradeNumber == req.TradeNumber && n.id != req.id))
{
throw new ServiceException($"交易编号'{req.TradeNumber}'已经存在");
}
else if (PS.Config.ErpElement.UpperTradeNumber)
{
trade.TradeNumber = req.TradeNumber.ToUpperInvariant();
}
trade.MetaDic = dbTrade.MetaDic;
InnerSaveEditTrade(trade, out var changeConfirmStatus);
var subTrades = DbContext.trade.Where(x => x.ParentTradeId == trade.id).ToList();
subTrades.ForEach(x =>
{
x.StructureType = trade.StructureType;
if (dbTrade.StructureType == "折价" && isDiffStructureType && PS.Config.Is国泰君安)
{
saveZheJiaTradeMarginTemplate(x, dbTrade);
}
});
DbContext.SaveChanges();
SaveTradeOperationHistory(trade, "修改组合交易");
using (var tagService = new TagService(OptUser))
{
tagService.SetTradeTagForTradeEdit(new TagModule.Dto.SetTradeTagForTradeEditRequest
{
TradeId = trade.id,
Tags = req.Tags
});
}
return trade;
}
else if (tradeIds == null || !tradeIds.Any())
{
throw new ServiceException("缺少子交易");
}
else
{
SetDBModelCreator(dbTrade);
DbContext.trade.Add(dbTrade);
dbTrade.TradeStatus = ConsTrade.新增待确认;
dbTrade.TradeSource = _source.ToString();
dbTrade.TradeType = "结构化交易";
dbTrade.IsGroup = 1;
var copyLeg = DbContext.trade.Where(x => tradeIds.Contains(x.id) && x.UnderlyingId > 0).First();
//dbTrade.MetaDic = new TradeMetaService(this).GetTradeMeta(copyLeg.id);
dbTrade.UnderlyingCode = copyLeg.UnderlyingCode;
if (!string.IsNullOrEmpty(dbTrade.UnderlyingCode))
{
var preHandler = new TradeSavePreHandler(this);
preHandler.PrepareUnderlying(dbTrade, false);
}
dbTrade.SpotPrice = copyLeg.SpotPrice;
dbTrade.ParticipationRate = 1;
dbTrade.CreateDate = DateTime.Now;
if (string.IsNullOrWhiteSpace(req.TradeNumber) && req.id == 0)
{
dbTrade.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(dbTrade, DbContext);
//没有期货报送成交编号添加到dictionary,有则修改该key的值
if (PS.Config.Is招证)
{
if (req.MetaDic == null)
{
req.MetaDic = new Dictionary();
}
if (dbTrade.MetaDic == null)
{
dbTrade.MetaDic = new Dictionary();
}
req.MetaDic["期货报送成交编号"] = dbTrade.TradeNumber;
dbTrade.MetaDic["期货报送成交编号"] = dbTrade.TradeNumber;
}
}
else if (DbContext.trade.Any(n => n.TradeNumber == req.TradeNumber && n.id != req.id))
{
throw new ServiceException($"交易编号'{req.TradeNumber}'已经存在");
}
else if (PS.Config.ErpElement.UpperTradeNumber)
{
dbTrade.TradeNumber = req.TradeNumber.ToUpperInvariant();
}
DbContext.SaveChanges();
//交易元数据
if (req.MetaDic.Any())
{
foreach (var kv in req.MetaDic)
{
if (!string.IsNullOrEmpty(kv.Value))
{
AddTradeMeta(true, dbTrade.id, kv.Key, kv.Value);
}
}
}
new TradeSaveExtend(this, true).Save(dbTrade, dbTrade);
var subTrades = DbContext.trade.Where(x => tradeIds.Contains(x.id)).ToList();
subTrades.ForEach(x =>
{
x.IsGroup = 2;
x.ParentTradeId = dbTrade.id;
x.StructureType = dbTrade.StructureType;
if (dbTrade.StructureType == "折价" && PS.Config.Is国泰君安)
{
saveZheJiaTradeMarginTemplate(x, dbTrade);
}
});
using (var tagService = new TagService(OptUser))
{
tagService.SetTradeTagForTradeEdit(new TagModule.Dto.SetTradeTagForTradeEditRequest
{
TradeId = dbTrade.id,
Tags = req.Tags
});
//subTrades.ForEach(d =>
//{
// tagService.SetTradeTagForTradeEdit(new TagModule.Dto.SetTradeTagForTradeEditRequest
// {
// TradeId = d.id,
// Tags = req.Tags
// });
//});
}
var subCashs = DbContext.ClientCashInCashOut.Where(x => x.TradeId != null && tradeIds.Contains(x.TradeId.Value)).ToList();
subCashs.ForEach(x =>
{
x.IsGroup = 2;
x.ParentTradeNumber = dbTrade.TradeNumber;
});
DbContext.SaveChanges();
SaveTradeOperationHistory(dbTrade, "新增组合交易");
var eodTrades = DbContext.eod_trade.Where(x => tradeIds.Contains(x.TradeId));
DbContext.eod_trade.RemoveRange(eodTrades);
DbContext.SaveChanges();
return dbTrade;
}
}
//新增交易保存
private trade InnerSaveNewTrade(trade req, bool tradeNumberGenerated)
{
if (req.ParentTradeId > 0 && req.TradeType == "收益互换")
{
var parentTrade = DbContext.trade.Find(req.ParentTradeId);
if (parentTrade != null && parentTrade.TradeType == "收益互换")
{
parentTrade.OriginalStockEqvNotional += req.StockEqvNotional;
parentTrade.StockEqvNotional += req.StockEqvNotional;
parentTrade.StockEqvNotionalReal += req.StockEqvNotional;
var tradePrice = (parentTrade.TradePrice ?? 0) * (parentTrade.BuySell == "买入" ? -1 : 1) + (req.TradePrice ?? 0) * (req.BuySell == "买入" ? -1 : 1);
parentTrade.TradePrice = Math.Abs(tradePrice);
parentTrade.BuySell = tradePrice >= 0 ? "卖出" : "买入";
}
}
var dbTrade = req.Clone();
dbTrade.trade_swap = req.trade_swap.Clone();
//if (double.IsNaN(dbTrade.TradeSinglePrice.Value)) dbTrade.TradeSinglePrice = 0;
//if (double.IsNaN(dbTrade.PremiumRate.Value)) dbTrade.PremiumRate = 0;
SetDBModelCreator(dbTrade);
DbContext.trade.Add(dbTrade);
//申万交易编号特殊处理(如果交易编号是用户手动输入时)
if (!tradeNumberGenerated && PS.Config.Is申万)
{
var client = DataCacheProvider.GetClientDataSource().GetData(dbTrade.ClientId);
if (client?.Code != null && dbTrade.TradeNumber.StartsWith(client.Code))
{
var canParseInt = int.TryParse(dbTrade.TradeNumber.Substring(client.Code.Length), out var contractNo);
if (canParseInt && contractNo > (client.CurrentContractNo ?? 0))
{
client.CurrentContractNo = contractNo;
}
}
}
if (req.TradeType == "收益互换" && req.IsGroup == 1)
{
InnerSaveTrade2(true, dbTrade, dbTrade, true);
if (req.get_trade_swap_details.Any())
{
var index = 1;
foreach (var detail in dbTrade.get_trade_swap_details)
{
var trade = req.Clone();
trade.get_trade_swap_details = new List();
trade.trade_swap = req.trade_swap.Clone();
if (!string.IsNullOrEmpty(detail.UnderlyingCode))
{
var preHandler = new TradeSavePreHandler(this);
trade.UnderlyingCode = detail.UnderlyingCode;
var underlying = preHandler.PrepareUnderlying(trade, false);
trade.trade_swap.SwapType = "普通";
trade.trade_swap.OriginalTradeId = dbTrade.id;
if (trade.trade_swap.IsPayFloatingProfit)
{
trade.trade_swap.GetTradePrice = detail.TradePrice;
}
else
{
trade.trade_swap.PayTradePrice = detail.TradePrice;
}
trade.trade_swap.GetLongShort = detail.LongShort;
trade.trade_swap.GetUnderlyingCode = detail.UnderlyingCode;
trade.trade_swap.GetUnderlyingId = trade.UnderlyingId;
trade.trade_swap.GetSpotPrice = detail.SpotPrice;
trade.trade_swap.GetNotional = detail.Notional;
trade.trade_swap.GetTradeAmount = trade.trade_swap.GetNotional / underlying.CountRatio;
trade.BuySell = (trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0) == 0 ? (trade.trade_swap.IsPayFloatingProfit ? "卖出" : "买入") : ((trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0) > 0 ? "卖出" : "买入");
trade.TradePrice = Math.Abs((trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0));
trade.OriginalNotional = detail.Notional;
trade.Notional = detail.Notional ?? 0;
trade.TradeAmount = trade.trade_swap.GetTradeAmount ?? 0;
trade.SpotPrice = detail.SpotPrice;
trade.StockEqvNotionalReal = trade.Notional * trade.SpotPrice ?? 0;
trade.OriginalStockEqvNotional = trade.StockEqvNotionalReal;
trade.StockEqvNotional = trade.StockEqvNotionalReal;
trade.ParentTradeId = dbTrade.id;
trade.TradeNumber = BizLogicSingleton.Instance.GenerateSubTradeNumberBeforeConfirm(trade, dbTrade, index, DbContext);
index++;
trade.IsGroup = 2;
trade.TradeStatus = ConsTrade.新增待确认;
trade.TradeSource = req.TradeSource;
trade.Comments = null;
SetDBModelCreator(trade);
DbContext.trade.Add(trade);
DbContext.SaveChanges();
detail.ChildTradeId = trade.id;
InnerSaveTrade2(true, trade, trade, true);
}
}
}
else if (req.pay_trade_swap_details.Any())
{
var index = 1;
foreach (var detail in req.pay_trade_swap_details)
{
var trade = req.Clone();
trade.pay_trade_swap_details = new List();
trade.trade_swap = req.trade_swap.Clone();
if (!string.IsNullOrEmpty(detail.UnderlyingCode))
{
var preHandler = new TradeSavePreHandler(this);
trade.UnderlyingCode = detail.UnderlyingCode;
var underlying = preHandler.PrepareUnderlying(trade, false);
trade.trade_swap.SwapType = "普通";
trade.trade_swap.OriginalTradeId = dbTrade.id;
if (trade.trade_swap.IsPayFloatingProfit)
{
trade.trade_swap.GetTradePrice = detail.TradePrice;
}
else
{
trade.trade_swap.PayTradePrice = detail.TradePrice;
}
trade.trade_swap.PayLongShort = detail.LongShort;
trade.trade_swap.PayUnderlyingCode = detail.UnderlyingCode;
trade.trade_swap.PayUnderlyingId = trade.UnderlyingId;
trade.trade_swap.PaySpotPrice = detail.SpotPrice;
trade.trade_swap.PayNotional = detail.Notional;
trade.trade_swap.PayTradeAmount = trade.trade_swap.PayNotional / underlying.CountRatio;
trade.BuySell = (trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0) == 0 ? (trade.trade_swap.IsPayFloatingProfit ? "卖出" : "买入") : ((trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0) > 0 ? "卖出" : "买入");
trade.TradePrice = Math.Abs((trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0));
trade.OriginalNotional = detail.Notional;
trade.Notional = detail.Notional ?? 0;
trade.TradeAmount = trade.trade_swap.PayTradeAmount ?? 0;
trade.SpotPrice = detail.SpotPrice;
trade.StockEqvNotionalReal = trade.Notional * trade.SpotPrice ?? 0;
trade.OriginalStockEqvNotional = trade.StockEqvNotionalReal;
trade.StockEqvNotional = trade.StockEqvNotionalReal;
trade.ParentTradeId = dbTrade.id;
trade.TradeNumber = BizLogicSingleton.Instance.GenerateSubTradeNumberBeforeConfirm(trade, dbTrade, index, DbContext);
index++;
trade.IsGroup = 2;
trade.TradeStatus = ConsTrade.新增待确认;
trade.TradeSource = req.TradeSource;
SetDBModelCreator(trade);
DbContext.trade.Add(trade);
DbContext.SaveChanges();
detail.ChildTradeId = trade.id;
InnerSaveTrade2(true, trade, trade, true);
}
}
}
}
else if (req.TradeType == "结构化交易" && req.IsGroup == 1)
{
var copyLeg = dbTrade.SubTrades.Where(x => x.UnderlyingId > 0).First();
dbTrade.MetaDic = copyLeg.MetaDic;
dbTrade.UnderlyingCode = copyLeg.UnderlyingCode;
if (!string.IsNullOrEmpty(dbTrade.UnderlyingCode))
{
var preHandler = new TradeSavePreHandler(this);
preHandler.PrepareUnderlying(dbTrade, false);
}
dbTrade.SpotPrice = copyLeg.SpotPrice;
dbTrade.StartDate = dbTrade.TradeDate;
dbTrade.SettlementDate = dbTrade.ExerciseDate;
var countRatio = (DataCacheProvider.GetUnderlyingDataSource().GetData(copyLeg.UnderlyingId)?.CountRatio) ?? 1;
if (dbTrade.IsUsePremiumRate == true)
{
dbTrade.OriginalStockEqvNotional = dbTrade.StockEqvNotional;
dbTrade.StockEqvNotionalReal = dbTrade.StockEqvNotional;
dbTrade.Notional = dbTrade.SpotPrice != 0 ? dbTrade.StockEqvNotionalReal / dbTrade.SpotPrice.Value : 0;
dbTrade.OriginalNotional = dbTrade.Notional;
dbTrade.TradeAmount = dbTrade.Notional / countRatio;
dbTrade.TradeSinglePrice = dbTrade.Notional != 0 ? dbTrade.TradePrice / dbTrade.Notional : 0;
dbTrade.PremiumRate = dbTrade.StockEqvNotional > 0 ? dbTrade.TradePrice / dbTrade.StockEqvNotional : 0;
}
else
{
if (dbTrade.TradeAmount > 0)
{
dbTrade.Notional = dbTrade.TradeAmount * countRatio;
}
else
{
dbTrade.TradeAmount = dbTrade.Notional / countRatio;
}
dbTrade.OriginalNotional = dbTrade.Notional;
dbTrade.StockEqvNotionalReal = dbTrade.Notional * dbTrade.SpotPrice.Value;
dbTrade.StockEqvNotional = dbTrade.StockEqvNotionalReal;
dbTrade.OriginalStockEqvNotional = dbTrade.StockEqvNotional;
}
dbTrade.Notional = dbTrade.TradeAmount * countRatio;
dbTrade.OriginalNotional = dbTrade.Notional;
dbTrade.ParticipationRate = 1;
dbTrade.CreateDate = DateTime.Now;
DbContext.SaveChanges();
//交易元数据
if (dbTrade.MetaDic.Any())
{
foreach (var kv in dbTrade.MetaDic)
{
if (!string.IsNullOrEmpty(kv.Value))
{
AddTradeMeta(true, dbTrade.id, kv.Key, kv.Value);
}
}
}
new TradeSaveExtend(this, true).Save(dbTrade, dbTrade);
foreach (var subTrade in req.SubTrades)
{
if (!string.IsNullOrEmpty(subTrade.UnderlyingCode))
{
var preHandler = new TradeSavePreHandler(this);
preHandler.PrepareUnderlying(subTrade, false);
}
subTrade.ParentTradeId = dbTrade.id;
subTrade.IsGroup = 2;
subTrade.TradeStatus = ConsTrade.新增待确认;
subTrade.TradeSource = dbTrade.TradeSource;
subTrade.StructureType = dbTrade.StructureType;
SetDBModelCreator(subTrade);
DbContext.trade.Add(subTrade);
InnerSaveTrade2(true, subTrade, subTrade, true);
}
DbContext.TradeAuditLog.Add(new TradeAuditLog
{
TradeId = dbTrade.id,
Changes = string.Empty,
DataType = "00",
OptType = _source == TradeSourceEnum.导入交易 ? "导入交易" : "新增交易",
OptId = UserId,
OptName = UserName,
OptDate = OptDate,
AuditFlag = TradeAuditFlag.operation
});
DbContext.SaveChanges();
}
else if (req.TradeType == "结构化交易")
{
var tradeNumber = dbTrade.TradeNumber;
//将子交易复制到主交易
var copyLeg = dbTrade.SubTrades.First();
if (copyLeg.StructureType == "三领口组合")
{
copyLeg = dbTrade.SubTrades.Skip(1).First();
}
UpdateEntity(dbTrade, copyLeg);
dbTrade.TradeNumber = tradeNumber;
dbTrade.TradeType = "结构化交易";
dbTrade.ExerciseDate = req.SubTrades.Max(n => n.ExerciseDate ?? DateTime.MinValue);
DbContext.SaveChanges();
if (copyLeg.MetaDic.ContainsKey("合约编号"))
{
AddTradeMeta(false, dbTrade.id, "合约编号", copyLeg.MetaDic["合约编号"]);
}
foreach (var subTrade in dbTrade.SubTrades)
{
subTrade.ParentTradeId = dbTrade.id;
subTrade.IsGroup = 0;
SetDBModelCreator(subTrade);
DbContext.trade.Add(subTrade);
InnerSaveTrade2(true, subTrade, subTrade, true);
}
}
else
{
InnerSaveTrade2(true, dbTrade, dbTrade, true);
}
return dbTrade;
}
private void saveZheJiaTradeMarginTemplate(trade subTrade, trade trade)
{
subTrade.InitialMargin = 0;
trade.InitialMargin = 0;
var marginTemplate = DbContext.margin_template_v2.FirstOrDefault(x => x.Name == "无预付金");
if (marginTemplate == null)
{
marginTemplate = new margin_template_v2()
{
Name = "无预付金",
MarginType = (int)MarginTypeV2Enum.单腿,
RuleType = (int)MarginRuleTypeEnum.无预付金,
TradeTypes = "香草期权,障碍期权,二元期权,亚式期权,彩虹期权,远期,双鲨期权,凤凰期权,雪球期权,气囊结构,收益互换,区间累积期权,合成价差期权,累计期权,自定义交易",
Comments = "预付金占用为零。",
IsDefault = false,
IsForClient = false,
IsValid = true,
BuySellType = BuySellEnum.All,
MarginScenarios = MarginScenarioEnum.All,
OptDate = DateTime.Now,
OptId = UserId,
OptName = UserName
};
DbContext.margin_template_v2.Add(marginTemplate);
DbContext.SaveChanges();
}
var tradeMarginTemplates = DbContext.trade_margin_template.Where(x => x.TradeId == subTrade.id);
DbContext.trade_margin_template.RemoveRange(tradeMarginTemplates);
var tradeMarginTemplate = new trade_margin_template()
{
TradeId = subTrade.id,
ValueDate = new DateTime(2000, 1, 1),
MarginTemplateId = marginTemplate.id,
IsLatest = true,
OptId = UserId,
OptName = UserName,
OptDate = DateTime.Now
};
DbContext.trade_margin_template.Add(tradeMarginTemplate);
DbContext.SaveChanges();
}
private trade InnerSaveEditSwapGroupTrade(trade req)
{
var details = req.get_trade_swap_details.Union(req.pay_trade_swap_details);
if (req.get_trade_swap_details.Any())
{
req.trade_swap.PayTradePrice = req.get_trade_swap_details.Sum(x => x.TradePrice ?? 0);
}
else if (req.pay_trade_swap_details.Any())
{
req.trade_swap.GetTradePrice = req.pay_trade_swap_details.Sum(x => x.TradePrice ?? 0);
}
var changeSwapDetails = false;
var tradeSwapDetails = DbContext.trade_swap_detail.Where(x => x.TradeId == req.id).ToList();
tradeSwapDetails.ForEach(x =>
{
var detail = details.FirstOrDefault(y => y.ChildTradeId == x.ChildTradeId);
if (detail == null)
{
changeSwapDetails = true;
}
else if (detail.UnderlyingCode != x.UnderlyingCode || detail.Notional != x.Notional || detail.SpotPrice != x.SpotPrice || detail.LongShort != x.LongShort || detail.TradePrice != x.TradePrice)
{
changeSwapDetails = true;
}
});
if (tradeSwapDetails.Count != details.Count())
{
changeSwapDetails = true;
}
//修改主交易信息
var dbTrade = InnerSaveEditTrade(req, out var changeConfirmStatus);
if (changeConfirmStatus)
{
changeSwapDetails = true;
}
if (changeSwapDetails)
{
//先删除子交易
var service = new TradeInvalidService(UserInfo);
var ids = new HashSet { dbTrade.id };
var subTrades = DbContext.trade.Where(x => x.ParentTradeId == req.id && x.ValidState != "InValid").ToList();
var subTradeIds = subTrades.Select(x => x.id).ToList();
var swaps = DbContext.trade_swap.Where(x => subTradeIds.Contains(x.TradeId)).ToList();
int? originalTradeId = null;
foreach (var subTrade in subTrades)
{
var swap = swaps.FirstOrDefault(x => x.TradeId == subTrade.id);
if (swap != null && swap.OriginalTradeId > 0)
{
originalTradeId = swap.OriginalTradeId;
}
ids.Add(subTrade.id);
service.InnerInvalidTrade(subTrade);
}
service.SetCommissionInVaild(ids);
//重新生成子交易
if (req.get_trade_swap_details.Any())
{
var index = 1;
foreach (var detail in req.get_trade_swap_details)
{
var trade = req.Clone();
trade.get_trade_swap_details = new List();
trade.trade_swap = req.trade_swap.Clone();
trade.trade_swap.OriginalTradeId = originalTradeId ?? dbTrade.id;
if (!string.IsNullOrEmpty(detail.UnderlyingCode))
{
var preHandler = new TradeSavePreHandler(this);
trade.UnderlyingCode = detail.UnderlyingCode;
var underlying = preHandler.PrepareUnderlying(trade, false);
trade.trade_swap.SwapType = "普通";
if (trade.trade_swap.IsPayFloatingProfit)
{
trade.trade_swap.GetTradePrice = detail.TradePrice;
}
else
{
trade.trade_swap.PayTradePrice = detail.TradePrice;
}
trade.trade_swap.GetLongShort = detail.LongShort;
trade.trade_swap.GetUnderlyingCode = detail.UnderlyingCode;
trade.trade_swap.GetUnderlyingId = trade.UnderlyingId;
trade.trade_swap.GetSpotPrice = detail.SpotPrice;
trade.trade_swap.GetNotional = detail.Notional;
trade.trade_swap.GetTradeAmount = trade.trade_swap.GetNotional / underlying.CountRatio;
trade.BuySell = (trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0) == 0 ? (trade.trade_swap.IsPayFloatingProfit ? "卖出" : "买入") : ((trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0) > 0 ? "卖出" : "买入");
trade.TradePrice = Math.Abs((trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0));
trade.OriginalNotional = detail.Notional;
trade.Notional = detail.Notional ?? 0;
trade.TradeAmount = trade.trade_swap.GetTradeAmount ?? 0;
trade.SpotPrice = detail.SpotPrice;
trade.StockEqvNotionalReal = trade.Notional * trade.SpotPrice ?? 0;
trade.OriginalStockEqvNotional = trade.StockEqvNotionalReal;
trade.StockEqvNotional = trade.StockEqvNotionalReal;
trade.ParentTradeId = dbTrade.id;
trade.TradeNumber = BizLogicSingleton.Instance.GenerateSubTradeNumberBeforeConfirm(trade, dbTrade, index, DbContext);
index++;
trade.IsGroup = 2;
trade.TradeStatus = ConsTrade.新增待确认;
trade.TradeSource = req.TradeSource;
trade.Comments = null;
SetDBModelCreator(trade);
DbContext.trade.Add(trade);
DbContext.SaveChanges();
detail.ChildTradeId = trade.id;
InnerSaveTrade2(true, trade, trade, true);
}
}
}
else if (req.pay_trade_swap_details.Any())
{
var index = 1;
foreach (var detail in req.pay_trade_swap_details)
{
var trade = req.Clone();
trade.pay_trade_swap_details = new List();
trade.trade_swap = req.trade_swap.Clone();
trade.trade_swap.OriginalTradeId = originalTradeId ?? dbTrade.id;
if (!string.IsNullOrEmpty(detail.UnderlyingCode))
{
var preHandler = new TradeSavePreHandler(this);
trade.UnderlyingCode = detail.UnderlyingCode;
var underlying = preHandler.PrepareUnderlying(trade, false);
trade.trade_swap.SwapType = "普通";
if (trade.trade_swap.IsPayFloatingProfit)
{
trade.trade_swap.GetTradePrice = detail.TradePrice;
}
else
{
trade.trade_swap.PayTradePrice = detail.TradePrice;
}
trade.trade_swap.PayLongShort = detail.LongShort;
trade.trade_swap.PayUnderlyingCode = detail.UnderlyingCode;
trade.trade_swap.PayUnderlyingId = trade.UnderlyingId;
trade.trade_swap.PaySpotPrice = detail.SpotPrice;
trade.trade_swap.PayNotional = detail.Notional;
trade.trade_swap.PayTradeAmount = trade.trade_swap.PayNotional / underlying.CountRatio;
trade.BuySell = (trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0) == 0 ? (trade.trade_swap.IsPayFloatingProfit ? "卖出" : "买入") : ((trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0) > 0 ? "卖出" : "买入");
trade.TradePrice = Math.Abs((trade.trade_swap.GetTradePrice ?? 0) - (trade.trade_swap.PayTradePrice ?? 0));
trade.OriginalNotional = detail.Notional;
trade.Notional = detail.Notional ?? 0;
trade.TradeAmount = trade.trade_swap.PayTradeAmount ?? 0;
trade.SpotPrice = detail.SpotPrice;
trade.StockEqvNotionalReal = trade.Notional * trade.SpotPrice ?? 0;
trade.OriginalStockEqvNotional = trade.StockEqvNotionalReal;
trade.StockEqvNotional = trade.StockEqvNotionalReal;
trade.ParentTradeId = dbTrade.id;
trade.TradeNumber = BizLogicSingleton.Instance.GenerateSubTradeNumberBeforeConfirm(trade, dbTrade, index, DbContext);
index++;
trade.IsGroup = 2;
trade.TradeStatus = ConsTrade.新增待确认;
trade.TradeSource = req.TradeSource;
SetDBModelCreator(trade);
DbContext.trade.Add(trade);
DbContext.SaveChanges();
detail.ChildTradeId = trade.id;
InnerSaveTrade2(true, trade, trade, true);
}
}
}
}
return dbTrade;
}
//修改交易保存
private trade InnerSaveEditTrade(trade req, out bool changeConfirmStatus)
{
var dbTrade = DbContext.trade.Find(req.id);
if (dbTrade == null)
{
throw new ServiceException("保存失败,数据不存在");
}
dbTrade.SalesCommission = new SalesCommissionDataService(OptUser).GetTradeCommissionInfo(dbTrade.id);
//默认都没填销售信息时,不影响交易状态变更,都赋值空,这样下面GetDataChanges就不会包含commission变更信息
if (dbTrade.SalesCommission?.SalesIds == null && req.SalesCommission?.SalesIds == null)
{
dbTrade.SalesCommission = null;
req.SalesCommission = null;
}
if (!ConsGlobal.IsValid(dbTrade.ValidState))
{
throw new NotSupportedException("不支持对已无效的交易进行修改:" + dbTrade.TradeNumber);
}
if (req.ParentTradeId > 0 && req.TradeType == "收益互换")
{
var parentTrade = DbContext.trade.Find(req.ParentTradeId);
if (parentTrade != null)
{
parentTrade.OriginalStockEqvNotional += req.StockEqvNotional - (dbTrade.OriginalStockEqvNotional ?? 0);
parentTrade.StockEqvNotional += req.StockEqvNotional - (dbTrade.OriginalStockEqvNotional ?? 0);
parentTrade.StockEqvNotionalReal += req.StockEqvNotional - (dbTrade.OriginalStockEqvNotional ?? 0);
var tradePrice = (parentTrade.TradePrice ?? 0) * (parentTrade.BuySell == "买入" ? -1 : 1) + (req.TradePrice ?? 0) * (req.BuySell == "买入" ? -1 : 1) - (dbTrade.TradePrice ?? 0) * (dbTrade.BuySell == "买入" ? -1 : 1);
parentTrade.TradePrice = Math.Abs(tradePrice);
parentTrade.BuySell = tradePrice >= 0 ? "卖出" : "买入";
}
}
else if (req.IsGroup == 2)
{
var parentTrade = DbContext.trade.Find(req.ParentTradeId);
if (parentTrade != null)
{
var tradePrice = (parentTrade.TradePrice ?? 0) * (parentTrade.BuySell == "买入" ? -1 : 1) + (req.TradePrice ?? 0) * (req.BuySell == "买入" ? -1 : 1) - (dbTrade.TradePrice ?? 0) * (dbTrade.BuySell == "买入" ? -1 : 1);
parentTrade.TradePrice = tradePrice * (parentTrade.BuySell == "买入" ? -1 : 1);
if (parentTrade.OriginalNotional != null && parentTrade.OriginalNotional != 0)
{
parentTrade.TradeSinglePrice = parentTrade.TradePrice / parentTrade.OriginalNotional;
}
if (parentTrade.OriginalStockEqvNotional != null && parentTrade.OriginalStockEqvNotional != 0)
{
parentTrade.PremiumRate = TradeHelper.GetPremiumRateByTradePrice(parentTrade.TradePrice, parentTrade.OriginalStockEqvNotional, parentTrade.ParticipationRate, parentTrade.PrincipalSum(), parentTrade.AnnualizeFactor, parentTrade.BuySell, parentTrade.TradeType, true);
}
}
}
if (valuedateBLL.SystemDate.EditTradeNeedRemark)
{
req.MetaDic.TryGetValue("remark", out var remark);
req.MetaDic.Remove("remark");
//记录审核日志
DbContext.TradeAuditLog.Add(new TradeAuditLog
{
TradeId = dbTrade.id,
Changes = remark,
DataType = "00",
OptId = UserId,
OptName = UserName,
OptDate = OptDate,
OptType = "修改交易",
AuditFlag = TradeAuditFlag.operation
});
}
//if (PS.Config.ErpElement.SecuritiesEnvironment && string.IsNullOrWhiteSpace(req.Comments))
//{
// throw new ServiceException("保存失败,交易编辑时,备注为必填字段");
//}
//使用明确的IsUsePremiumRate布尔值
if (!req.IsUsePremiumRate.HasValue && dbTrade.IsUsePremiumRate.HasValue)
{
req.IsUsePremiumRate = false;
}
req.CalcFlag = dbTrade.CalcFlag;
var oldClientId = dbTrade.ClientId;
var oldTradeStatus = dbTrade.TradeStatus;
var tradeDateChanged = dbTrade.TradeDate != req.TradeDate;
//移除价格观察
if (dbTrade.UnderlyingId != req.UnderlyingId)
{
RemoveEntities(x => x.TradeId == req.id);
}
//移除观察日
if (dbTrade.TradeType == "凤凰期权")
{
RemoveEntities(x => x.TradeId == dbTrade.id);
}
//移除可能的TradeMeta中组合标的信息
RemoveEntities(x => x.TradeId == dbTrade.id && x.MetaKey.StartsWith(ConsTradeMetaKey.SyntheticUnderlying));
//交易编号调整
var canGenerateTradeNumber = false;
if (req.ValidState == "InValid")
{
if (!string.IsNullOrWhiteSpace(dbTrade.TradeNumber))
{
new TradeDocumentDataService(this).DeleteConfirmBook(dbTrade.id);
if (dbTrade.TradeNumber.StartsWith("CW"))
{
req.TradeNumber = dbTrade.TradeNumber.Replace("CW", "XX");
}
else // if (PS.Config.Is光大光子)
{
req.TradeNumber = dbTrade.TradeNumber.Insert(0, "XX");
}
}
}
else
{
canGenerateTradeNumber = string.IsNullOrWhiteSpace(req.TradeNumber);
if (canGenerateTradeNumber)
{
req.TradeNumber = dbTrade.TradeNumber;
}
}
req.ContractVersion = dbTrade.ContractVersion;
req.PairTrade = dbTrade.PairTrade;
req.CreateDate = dbTrade.CreateDate;
//确认成交状态的交易修改后变为原始标记
req.DividendDate = new DateTime(2000, 1, 1);
//记录交易变更信息
var changsStr = string.Empty;
changeConfirmStatus = true;
TradeAuditFlag auditFlag = 0;
tradeBLL.SetFieldsByTradeType(dbTrade);
if (req.TradeType == "障碍期权")
{
req.trade_barrier_option.KnockInOutNotional = dbTrade.trade_barrier_option.KnockInOutNotional;
req.trade_barrier_option.KnockInOutDate = dbTrade.trade_barrier_option.KnockInOutDate;
}
var changes = DataChangeHelper.GetDataChanges(dbTrade, req);
if (req.TradeType == "远期" && changes.Any())
{
changes = changes.Where(x => x[0] != "TradeSinglePrice" && x[0] != "TradeSinglePriceString").ToList();
foreach (var item in changes)
{
if (item[0] == "OptionType")
{
item[1] = "多头空头";
item[2] = item[2].Replace("看涨", "多头").Replace("看跌", "空头");
item[3] = item[3].Replace("看涨", "多头").Replace("看跌", "空头");
}
else if (item[0] == "TradePrice")
{
item[1] = "开仓总费用";
}
}
}
var dbTradeMeta = DbContext.TradeMeta.Where(a => a.TradeId == dbTrade.id).ToDictionary(a => a.MetaKey, b => b.MetaValue);
var changMetas = new List>();
var keys = new string[] { "ExchangeRate", "交易场所", "清算机构", "主协议编号", "补充协议编号", "中央对手方清算", "中央清算平台", "交易平台", "收取周期", "支付周期", "敲入观察周期", "敲出观察周期" };
foreach (var key in keys)
{
bool isdbMeta = dbTradeMeta.TryGetValue(key, out string oldVal);
bool isreqMeta = req.MetaDic.TryGetValue(key, out string newVal);
if (!isdbMeta && !isreqMeta || oldVal == newVal || (string.IsNullOrWhiteSpace(oldVal) && string.IsNullOrWhiteSpace(newVal)))
{
continue;
}
var changeMeta = new List() { "", key, oldVal, newVal };
changMetas.Add(changeMeta);
}
if (changMetas.Any())
{
changes.AddRange(changMetas);
}
changsStr = changes.ToJson();
TradeHelper2.ReduceTradeExt(dbTrade);
TradeHelper2.ReduceTradeExt(req);
if (dbTrade.TradeStatus != ConsTrade.新增待确认)
{
//var changes = TradeChangeUtil.GetAllChanges(dbTrade, req);
//changsStr = TradeChangeUtil.SerializeChanges(changes, out auditFlag);
if (PS.Config.Company == CompanyEnum.东莞)
{
changeConfirmStatus = changes.Any();
}
else
{
//修改备注和簿记不需要提交审核和审批
changeConfirmStatus = !changes.All(n => string.IsNullOrEmpty(n[0]) || n[0] == nameof(trade.Comments)
|| n[0] == nameof(trade.AssetId) || n[0] == nameof(trade.AssetBookName));
}
}
//记录审核日志
DbContext.TradeAuditLog.Add(new TradeAuditLog
{
TradeId = dbTrade.id,
Changes = changsStr,
DataType = "C02",
OptId = UserId,
OptName = UserName,
OptDate = OptDate,
OptType = "修改交易",
AuditFlag = TradeAuditFlag.operation | auditFlag
});
//清除累计期权换月设置
ClearAccumulatorChangeDatas(dbTrade, req);
//更新数据库实体
UpdateEntity(dbTrade, req);
//交易状态处理
if (dbTrade.CheckTradeUpdate == Convert.ToInt32(TradeCheckEnum.StatusOfNew) || dbTrade.TradeStatus == ConsTrade.确认成交)
{
if (changeConfirmStatus)
{
dbTrade.TradeStatus = ConsTrade.修改待确认;
dbTrade.CheckTradeUpdate = Convert.ToInt32(TradeCheckEnum.StatusOfOld);
dbTrade.CheckStatus = null;
}
}
else if (dbTrade.TradeStatus != ConsTrade.修改待确认)
{
dbTrade.TradeStatus = ConsTrade.新增待确认;
dbTrade.CheckTradeUpdate = Convert.ToInt32(TradeCheckEnum.StatusOfOld);
dbTrade.CheckStatus = null;
//如果是新增待确认并且修改了客户,需要重新生成交易编号
if (oldClientId != dbTrade.ClientId && canGenerateTradeNumber)
{
dbTrade.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(dbTrade, DbContext);
}
}
if (changeConfirmStatus)
{
if (dbTrade.TradeType == "障碍期权")
{
req.trade_barrier_option.KnockInOutNotional = null;
req.trade_barrier_option.KnockInOutDate = null;
req.trade_barrier_option.KnockInOutStatus = null;
}
else if (req.TradeType == "气囊结构")
{
req.trade_airbag.KnockInOutStatus = null;
req.trade_airbag.KnockInOutDate = null;
req.trade_airbag.KnockInOutNotional = null;
}
}
dbTrade.TradeOldStatus = oldTradeStatus;
//修改结构化交易父交易的状态
if (dbTrade.ParentTradeId > 0 && dbTrade.IsGroup == 0)
{
var parentTrade = DbContext.trade.FirstOrDefault(n => n.id == dbTrade.ParentTradeId);
if (parentTrade != null)
{
SetParentTrade(dbTrade, parentTrade);
//结构化交易子交易修改了交易编号的处理(需要用户自己规范交易编号,必须带有横杠分隔符)
if (!string.IsNullOrWhiteSpace(req.TradeNumber) && !req.TradeNumber.StartsWith(parentTrade.TradeNumber))
{
UpdateStructureTradeNumbers(parentTrade, dbTrade);
}
}
}
//配对交易数据同步修改
if (!string.IsNullOrWhiteSpace(dbTrade.PairTrade))
{
SetPairTrade(dbTrade);
}
//重置历史数据(20210928:如果是当天修改也支持重置)
var resetHisData = dbTrade.TradeStatus == "新增待确认" || tradeDateChanged || valuedateBLL.ValueDate == dbTrade.TradeDate;
if (resetHisData)
{
dbTrade.TradeSavedVol = PS.Config.Is厦门象屿 ? dbTrade.TradeCloseVolatility : dbTrade.TradeOpenVolatility;
if (PS.Config.ErpElement.VolMode == Configuration.VolModeEnum.VolSurface)
{
dbTrade.TradeSavedVol = dbTrade.Vol;
}
}
new ExtensionTimeService(UserInfo, DbContext).DelExtensionTime(dbTrade.id, DateTime.MinValue, false);
InnerSaveTrade2(false, dbTrade, req, resetHisData, changeConfirmStatus);
return dbTrade;
}
//用于交易(不能是结构化主交易)入库后续处理
//changeConfirmStatus:保存交易修改时需要
private void InnerSaveTrade2(bool isAddNew, trade dbTrade, trade req, bool resetHisData, bool changeConfirmStatus = false)
{
//System.Diagnostics.Debug.Assert(dbTrade.TradeType != "结构化交易");
//期初价格确认状态(20210720:等需要时再放开)
//SetInitialSpotPriceState(isAddNew, dbTrade);
//保存修改
DbContext.SaveChanges();
//扩展数据保存
new TradeSaveExtend(this, isAddNew).Save(req, dbTrade);
//保存历史数据(新增或交易状态为新增待确认或交易日期变更)
if (resetHisData)
{
SaveHisDataForNewTrade(dbTrade);
}
//交易元数据
if (req.MetaDic.Any())
{
foreach (var kv in req.MetaDic)
{
if (isAddNew)
{
if (!string.IsNullOrEmpty(kv.Value))
{
AddTradeMeta(false, dbTrade.id, kv.Key, kv.Value);
}
}
else
{
AddOrUpdateTradeMeta(false, dbTrade.id, kv.Key, kv.Value);
}
}
}
if (isAddNew)
{
var auditLog = new TradeAuditLog
{
TradeId = dbTrade.id,
Changes = string.Empty,
DataType = "00",
OptType = "新增交易",
OptId = UserId,
OptName = UserName,
OptDate = OptDate,
AuditFlag = TradeAuditFlag.operation
};
if (_source == TradeSourceEnum.导入交易)
{
auditLog.OptType = "导入交易";
}
//记录审核日志
DbContext.TradeAuditLog.Add(auditLog);
}
else if (changeConfirmStatus)
{
//删除交易确认书
new TradeDocumentDataService(this).DeleteBooksAfterEditTrade(dbTrade);
//保存客户资金
new ClientCashInCashOutService(this).SaveClientCashInCashOut(dbTrade);
//删除票息记录
DbContext.autocall_observation.RemoveRange(DbContext.autocall_observation.Where(n => n.TradeId == dbTrade.id));
}
//删除E/Bod_Trade记录(tradedate也可能会被修改)
//如果修改不需要修改确认状态,客户资金相关数据不删除
RemoveEodTradeAndFutureInfo(false, dbTrade.id, changeConfirmStatus ? DateTime.MinValue : DateTime.MaxValue, deleteOtherCashs: true);
if (dbTrade.InitialMargin == null && dbTrade.TradeType != "自定义交易" && dbTrade.TradeType != "结构化交易" && ((req.IsGroup != 1 && dbTrade.TradeType != "收益互换") || (req.IsGroup != 2 && dbTrade.TradeType == "收益互换")))
{
dbTrade.InitialMargin = MarginDefault.GetInitialMarginWithPreHandle(dbTrade);
}
DbContext.SaveChanges();
}
//配对交易数据同步修改
private void SetPairTrade(trade dbTrade)
{
var id = Convert.ToInt32(dbTrade.PairTrade);
var pairTrade = DbContext.trade.Find(id);
pairTrade.UnderlyingId = dbTrade.UnderlyingId;
pairTrade.UnderlyingCode = dbTrade.UnderlyingCode;
pairTrade.UnderlyingAssetClass = dbTrade.UnderlyingAssetClass;
pairTrade.UnderlyingAssetName = dbTrade.UnderlyingAssetName;
pairTrade.UnderlyingInstrumentType = dbTrade.UnderlyingInstrumentType;
pairTrade.BuySell = dbTrade.BuySell == "买入" ? "卖出" : "买入";
pairTrade.ExerciseMode = dbTrade.ExerciseMode;
pairTrade.OptionType = dbTrade.OptionType;
pairTrade.StartDate = dbTrade.StartDate;
pairTrade.ExerciseDate = dbTrade.ExerciseDate;
pairTrade.Strike = dbTrade.Strike;
pairTrade.StockEqvNotional = dbTrade.StockEqvNotional;
// 场内期权交易不应该有标的期初价格
pairTrade.SpotPrice = dbTrade.TradeType == "场内期权" ? null : dbTrade.SpotPrice;
pairTrade.Notional = dbTrade.Notional;
pairTrade.OriginalNotional = dbTrade.OriginalNotional;
pairTrade.OriginalStockEqvNotional = dbTrade.OriginalStockEqvNotional;
pairTrade.TradeAmount = dbTrade.TradeAmount;
pairTrade.TradePrice = pairTrade.PremiumRate == null || pairTrade.PremiumRate <= 0 ? pairTrade.TradePrice : (pairTrade.StockEqvNotional * pairTrade.PremiumRate);
pairTrade.TradeSinglePrice = TradeHelper.GetTradeSinglePriceByTradePrice(pairTrade.TradePrice, pairTrade.Notional, pairTrade.OriginalPrincipalSum, pairTrade.BuySell, pairTrade.TradeType, true);
}
//为新增交易保存历史数据(持仓平仓波动率、对冲波动率、分红率、无风险利率)
private void SaveHisDataForNewTrade(trade tr)
{
if (tr.id < 1)
{
throw new ServiceException("trade id不正确");
}
var valueDate = tr.TradeDate ?? DateTime.Today;
if (tr.TradeType != "远期" && tr.TradeType != "收益互换" && tr.TradeType != "现金流交易")
{
//----------------------------------
// trade_volatility
//----------------------------------
_ = RemoveEntities(x => x.TradeId == tr.id);
if (PS.Config.ErpElement.VolMode == VolModeEnum.VolSurface)
{
tr.TradeSavedVol ??= tr.Vol;
tr.TradeOpenVolatility ??= tr.Vol;
tr.TradeCloseVolatility ??= tr.Vol;
tr.NumOfSmoothingDays = 1;
}
var tradVolatility = new TradeVolatility
{
TradeId = tr.id,
ValueDate = valueDate,
OptId = tr.OptId,
OptName = tr.OptName,
OptDate = DateTime.Now,
NumOfSmoothingDays = tr.NumOfSmoothingDays,
TradeCloseVolatility = tr.TradeCloseVolatility,
TradePositionVolatility = tr.TradeOpenVolatility,
IsFromTradeAdd = true
};
DbContext.TradeVolatility.Add(tradVolatility);
if (PS.Config.Company == Configuration.CompanyEnum.光大光子 && tradVolatility.TradePositionVolatility.HasValue
&& NumberHelper.TryParse(PS.Config.ErpElement.TradeOpenVolOff, out var d, out var isPercent) && d <= 1)
{
var openVol = tr.TradeOpenVolatility.Value;
//开仓波动率高于目标波动率,则减点,否则加点
var positionVol = openVol - (openVol - tr.TradeCloseVolatility.Value) * d;
//第一天使用折扣后的波动率(对冲+持仓)
tr.TradeSavedVol = tradVolatility.TradePositionVolatility = positionVol;
var clone = tradVolatility.Clone();
//第一天使用折扣后的波动率(不要平滑处理)
tradVolatility.NumOfSmoothingDays = 1;
tradVolatility.TradeCloseVolatility = positionVol;
//第一天之后使用平滑波动率
clone.ValueDate = QdpModule.QdpCalendarHelper.GetNonHoliday(tradVolatility.ValueDate.AddDays(1));
DbContext.TradeVolatility.Add(clone);
}
//----------------------------------
// trade_hedge_vol
//----------------------------------
_ = RemoveEntities(x => x.TradeId == tr.id);
var hedgeTradeVol = new trade_hedge_vol
{
TradeId = tr.id,
ValueDate = valueDate,
OptId = tr.OptId,
OptName = tr.OptName,
OptDate = DateTime.Now,
TradeSavedVol = tr.TradeSavedVol ?? 0
};
DbContext.trade_hedge_vol.Add(hedgeTradeVol);
}
//----------------------------------
// trade_hisdata:NoRiskRate + DividendRate
//----------------------------------
RemoveEntities(x => x.TradeId == tr.id);
var hisDataNoRisk = new TradeHisData
{
TradeId = tr.id,
ValueDate = valueDate,
ValueType = ConsTradeField.NoRiskRate,
Value = tr.NoRiskRate ?? ((valuedateBLL.SystemDate.RiskFreeRate ?? 0) / 100),
OptId = tr.OptId,
OptName = tr.OptName,
OptDate = DateTime.Now
};
DbContext.TradeHisData.Add(hisDataNoRisk);
if (hisDataNoRisk.Value < 1e-5)
{
LogFactory.GetLogger(nameof(SaveHisDataForNewTrade)).Info($"[NoRiskRate]{tr.id}--{tr.NoRiskRate}--{valuedateBLL.SystemDate.RiskFreeRate}--{tr.OptName}");
}
if (tr.DividendRate.HasValue)
{
var hisDataDividendRate = new TradeHisData
{
TradeId = tr.id,
ValueDate = valueDate,
ValueType = ConsTradeField.DividendRate,
Value = tr.DividendRate.Value,
OptId = tr.OptId,
OptName = tr.OptName,
OptDate = DateTime.Now,
};
DbContext.TradeHisData.Add(hisDataDividendRate);
}
}
//结构化交易子交易修改了交易编号的处理
private void UpdateStructureTradeNumbers(trade parentTrade, trade saveTrade)
{
//浙期的子交易编号中不包含-,分腿编号是最后一位数字
var index = PS.Config.Company == Configuration.CompanyEnum.浙期 ? saveTrade.TradeNumber.Length - 1 : saveTrade.TradeNumber.LastIndexOf('-');
if (index < 1)
{
return;
}
//修改父交易的交易编号
parentTrade.TradeNumber = saveTrade.TradeNumber.Substring(0, index);
//修改兄弟交易的交易编号
var siblingTds = DbContext.trade.Where(n => n.id != saveTrade.id && n.ParentTradeId == parentTrade.id).ToArray();
foreach (var std in siblingTds)
{
index = PS.Config.Company == Configuration.CompanyEnum.浙期 ? std.TradeNumber.Length - 1 : std.TradeNumber.LastIndexOf('-');
if (index > 0)
{
std.TradeNumber = parentTrade.TradeNumber + std.TradeNumber.Substring(index);
}
}
}
//清除累计期权换月设置
private void ClearAccumulatorChangeDatas(trade dbTrade, trade req)
{
if (dbTrade.TradeType != "累计期权")
{
return;
}
var changed = dbTrade.TradeType != req.TradeType
|| dbTrade.TradeDate != req.TradeDate
|| dbTrade.ExerciseDate != req.ExerciseDate
|| dbTrade.Strike != req.Strike
|| dbTrade.UnderlyingCode != req.UnderlyingCode
|| dbTrade.trade_accumulator_option.PayoffType != req.trade_accumulator_option.PayoffType
|| dbTrade.trade_accumulator_option.KOBarrier != req.trade_accumulator_option.KOBarrier
|| dbTrade.trade_accumulator_option.KOObservationDates != req.trade_accumulator_option.KOObservationDates;
if (!changed)
{
return;
}
var actions = DbContext.TradeAction.Where(n => n.TradeId == dbTrade.id && n.IsValid && n.ActionType == TradeActionType.AccumulatorChange).ToArray();
foreach (var action in actions)
{
action.IsValid = false;
}
}
}
}
//从远期交易保存上拷贝而来,暂时备份看看是否有用
//if (dbTrade.CheckTradeUpdate == Convert.ToInt32(TradeCheckEnum.StatusOfNew))
//{
// dbTrade.TradeStatus = ConsTrade.修改待确认;
//}
//else
//{
// if (dbTrade.TradeStatus == ConsTrade.审批中)
// {
// dbTrade.ProcessOrderId = 1;
// dbTrade.ProcessOptDate = DateTime.Now;
// dbTrade.ProcessStatus = "审批中";
// dbTrade.TradeStatus = ConsTrade.新增待确认;
// }
// if (dbTrade.TradeStatus == ConsTrade.已拒绝)
// {
// if (dbTrade.CheckTradeUpdate == Convert.ToInt32(TradeCheckEnum.StatusOfNew))
// {
// dbTrade.TradeStatus = ConsTrade.修改待确认;
// }
// else
// {
// dbTrade.TradeStatus = ConsTrade.新增待确认;
// }
// dbTrade.ProcessOrderId = 0;
// dbTrade.ProcessOptDate = DateTime.Now;
// dbTrade.ProcessStatus = "未审批";
// }
//}