using Microsoft.EntityFrameworkCore.Storage;
using YLErp.BLL;
using YLErp.BLL.Eod;
using YLErp.Commons;
using YLErp.CustomizedBizLogic;
using YLErp.DBModels.Consts;
using YLErp.DBModels.Helpers;
using YLErp.Enums;
using YLErp.Model;
using YLErp.Model.Enum;
using YLErp.Modules.ClientModule;
using YLErp.Modules.EodModule;
using YLErp.Modules.TradeDalModule;
using YLErp.QdpModule;
namespace YLErp.Modules.TradeModule.DealModule
{
///
/// 交易平仓操作
///
public class TradeUnwindService : TradeCashService
{
public TradeUnwindService(YLBaseService baseService) : base(baseService)
{
}
public TradeUnwindService(OptUserInfo userInfo) : base(userInfo)
{
}
///
/// isPairTrade是否 配对交易平仓
/// 规则:配对被执行的那一条的amount(trade_cash表格)和money(clientcashincashout 表格)应该是手动执行那一条的数值*-1
///
public trade_cash UnwindTrade(trade td, TradeCashReq req, bool isFromRecheck = false, bool isFromExercise = false)
{
if (td is null)
{
throw new ArgumentNullException(nameof(td));
}
if (td.TradeType == "结构化交易")
{
throw new ServiceException("操作失败,结构化交易主交易不支持此操作");
}
if (ConsTrade.TradeCompleteStatus.Contains(td.TradeStatus))
{
throw new ServiceException("操作失败,交易已了结!");
}
if (PS.Config.TradeElement.ExecuteAfterGeneratedConfirmDoc && !td.HasGeneratedConfirmBook())
{
if (td.TradeType != "远期" && td.TradeType != "自定义交易" && td.TradeType != "现金流交易")//临时写法,需要完善远期确认书
{
throw new ServiceException("请先去生成交易确认书");
}
}
//是否部分平仓
var isPartialClose = true;
var tradeCashInvalid = DbContext.trade_cash.FirstOrDefault(t => t.TradeId == td.id && t.Action == ClientCashInCashOut.系统操作_平仓费 && t.ValidState == ConsGlobal.InValid && !t.IsDeleted);
if (req != null)
{
unwindPreHandle(req, td, isFromExercise, out isPartialClose);
}
else
{
if (td.IsUsePremiumRate == true)
{
if (tradeCashInvalid != null &&
td.OriginalStockEqvNotional > 0
&& (tradeCashInvalid.UnwindPercentRate >= td.StockEqvNotional / td.OriginalStockEqvNotional || tradeCashInvalid.UnwindType == "全部平仓"))
{
isPartialClose = false;
}
}
else
{
if (tradeCashInvalid != null && (tradeCashInvalid.UnwindNotional >= td.Notional || tradeCashInvalid.UnwindType == "全部平仓"))
{
isPartialClose = false;
}
}
}
td.OptId = UserId;
td.OptName = UserName;
td.OptDate = DateTime.Now;
if (req != null)
{
td.UnWindNotional = req.UnwindNotional;
}
else
{
td.UnWindNotional = tradeCashInvalid == null ? 0 : tradeCashInvalid.UnwindNotional;
}
if (isPartialClose)
{
td.TradeStatus = ConsTrade.确认成交;
if (td.TradeType == "累计期权" && !isFromExercise)
{
var unwindPercent = (td.UnWindNotional ?? 0) / td.Notional;
var accumulator = DbContext.trade_accumulator_option.FirstOrDefault(x => x.TradeId == td.id);
if (accumulator != null)
{
accumulator.AccumuTradeAmount -= accumulator.OriginalAccumuTradeAmount * unwindPercent;
}
}
td.Notional -= (td.UnWindNotional ?? 0);
if (td.TradeType != "现金流交易")
{
var CountRatio = UnderlyingDataProvider.GetCountRatio(td.UnderlyingCode);
td.TradeAmount = td.Notional / CountRatio;
}
else
{
td.TradeAmount -= (tradeCashInvalid == null ? 0 : tradeCashInvalid.UnwindNotional ?? 0);
}
if (td.IsUsePremiumRate == true)
{
if (req != null)
{
td.StockEqvNotional -= (td.OriginalStockEqvNotional * req.UnwindPercentRate) ?? 0;
}
else
{
td.StockEqvNotional -= (td.OriginalStockEqvNotional * tradeCashInvalid.UnwindPercentRate) ?? 0;
}
}
else
{
if (td.TradeType == "远期" && PS.Config.ErpElement.ForwardTradePriceModel == 0 && !string.IsNullOrWhiteSpace(td.BasisUnderlyingCode))
{
td.StockEqvNotional -= TradeHelper.GetStockEqvNotional((req != null ? req.UnwindNotional : tradeCashInvalid.UnwindNotional) / td.OriginalNotional * td.OriginalStockEqvNotional, 1, 1);
}
else
{
td.StockEqvNotional = TradeHelper.GetStockEqvNotional(Math.Abs(td.Notional * (td.SpotPrice ?? 0.0)), td.ParticipationRate, td.AnnualizeFactor);
}
}
//td.PrincipalSum = TradeHelper.GetPrincipalSumReal(td.StockEqvNotional, td.OriginalStockEqvNotional, td.OriginalPrincipalSum);
td.HasPartialUnWind = 1;
}
else if (isFromExercise)
{
td.TradeStatus = ConsTrade.已执行;
}
else
{
td.TradeStatus = ConsTrade.已平仓;
}
//增加现金交割交易记录
var tc = CloseTrade_TradeCashSave(td, req, isFromRecheck, !isFromExercise, !isPartialClose);
if (!isPartialClose)
{
td.Notional = 0;
td.TradeAmount = 0;
td.StockEqvNotional = 0;
}
var groupAction = DbContext.trade_cash_group_action.FirstOrDefault(x => x.TradeId == td.id && x.Status != "已完成");
if (groupAction != null)
{
groupAction.Status = "已完成";
tc.ParentTradeCashId = groupAction.ParentTradeCashId;
tc.ParentTradeId = groupAction.ParentTradeId;
}
tc.ValidState = "Valid";
tc.ExerciseWay = TradeCashExerciseWayEnum.提前终止行权;
//加入平仓份额和平仓日期
td.UnWindDate = tc.ValueDate;
td.FinalPrice = tc.FinalPrice;
if (td.TradeType != "收益互换")
{
new TradeCashService(this).SaveTradeCashDetail(tc);
}
// if (isPairTrade) req.UnwindNotional = req.UnwindNotional * -1;
var dt = (td.TradeType == "远期" || td.TradeType == "掉期") && PS.Config.Is浙期 && td.ExerciseDate == tc.ValueDate ? td.SettlementDate : tc.ValueDate;
//增加出入金记录
new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, tc, dt);
AddTradeOperationHistoryAndSetParentTradeInfo(false, td, isPartialClose ? "部分平仓" : "全部平仓");
//删除E/Bod数据
RemoveEodTradeAndFutureInfo(false, td.id, tc.ValueDate);
DbContext.SaveChanges();
return tc;
}
///
/// 来自:UnwindTradeJson
///
public TradeUnwindResultModel UnwindTrade(TradeCashReq req, IDbContextTransaction trans = null)
{
if (req?.ValueDate == null)
{
throw new Exception("平仓日期不应为空");
}
//修改交易主表信息交易状态为已执行
var td = DbContext.trade.Find(req.TradeId);
var valueDate = SystemValueDate;
//从页面操作上来看,req.ValueDate是无用的
//当有用的时候需要赋值给valueDate
if (req.ValueDate.HasValue)
{
if (req.ValueDate < td.TradeDate)
{
throw new ServiceException("平仓日期不能小于交易日期");
}
if (req.ValueDate > valueDate)
{
throw new ServiceException("平仓日期不能大于系统日期");
}
}
valueDate = req.ValueDate ?? valueDate;
var isFromRecheck = false;
trade_cash tc = null;
var notrans = trans == null;
if (notrans)
{
trans = DbContext.Database.BeginTransaction();
}
try
{
//平仓复核逻辑验证
if ((valuedateBLL.SystemDate.CloseReCheck == 1) && td.TradeStatus == ConsTrade.平仓待复核)
{
//检查平仓单价
tc = DbContext.trade_cash.OrderByDescending(x => x.id).FirstOrDefault(dd => dd.TradeId == req.TradeId && dd.Action == ClientCashInCashOut.系统操作_平仓费 && dd.ValidState == ConsGlobal.InValid && !dd.IsDeleted).Clone();
if (td.TradeType == "远期")
{
if (req.FinalPrice != tc.FinalPrice)
{
throw new ServiceException("远期交易,标的价格不一致!复核不通过");
}
if (req.ValueDate != tc.ValueDate)
{
throw new ServiceException("远期交易,平仓日期不一致!复核不通过");
}
}
if (valuedateBLL.SystemDate.UnwindSinglePriceAngle == 1)
{
//添加根据交易方向判断资金方向
tc.UnwindPrice = tc.UnwindPrice * (td.TradeType == "远期" || ConsTrade.HasMinusValueOptions.Contains(td.TradeType) ? 1 : EodOperationBase.GetSign(td.BuySell));
tc.UnwindPricePercentRate = tc.UnwindPricePercentRate * (td.TradeType == "远期" || ConsTrade.HasMinusValueOptions.Contains(td.TradeType) ? 1 : EodOperationBase.GetSign(td.BuySell));
}
else
{
//添加根据交易方向判断资金方向
tc.UnwindPrice = tc.UnwindPrice * (td.TradeType == "远期" || !ConsTrade.HasMinusValueOptions.Contains(td.TradeType) ? 1 : EodOperationBase.GetSign(td.BuySell));
tc.UnwindPricePercentRate = tc.UnwindPricePercentRate * (td.TradeType == "远期" || !ConsTrade.HasMinusValueOptions.Contains(td.TradeType) ? 1 : EodOperationBase.GetSign(td.BuySell));
}
if (valuedateBLL.SystemDate.UnwindAmountAngle == 0)
{
tc.Amount = tc.Amount * (td.TradeType == "远期" || td.TradeType == "收益互换" ? 1 : EodOperationBase.GetSign(td.BuySell));
tc.QuoteAmount = tc.QuoteAmount * (td.TradeType == "远期" || td.TradeType == "收益互换" ? 1 : EodOperationBase.GetSign(td.BuySell));
}
if (req.AmountCheck == (tc.QuoteAmount ?? tc.Amount) || req.UnwindPricePercentRateCheck == tc.UnwindPricePercentRate && req.UnwindPricePercentRateCheck != null || req.UnwindPriceCheck == tc.UnwindPrice && req.UnwindPriceCheck != null)
{
req.UnwindPercentRate = (tc.UnwindPercentRate * 100) ?? req.UnwindPercentRate;
isFromRecheck = true;
td.CheckStatus = Convert.ToInt32(TradeCheckEnum.StatusOfUnwind);
td.UnWindDate = valueDate;
DbContext.SaveChanges();
}
else
{
//审核失败
throw new ServiceException("平仓费不一致!复核不通过");
}
}
var result = new TradeUnwindResultModel(td);
//存在审批流程时,走审批成功流程(需求②:按交易状态查对应流程)
if (valuedateBLL.SystemDate.CloseReApprove == 1 && TradeProcessCountByCategory(td) > 0)
{
result.ApprovalProcess = true;
var reqModel = new TradeOpenReqModel
{
tradeId = td.id,
status = "pass",
comments = "平仓复核审批成功",
ignoreMoneyCheck = false,
notNeedOperationHistory = true
};
var openResult = new TradeOpenService(this).UpdateTradeProcessLog(reqModel);
if (openResult.RetCode != TradeOpenRetCode.Success && !string.IsNullOrWhiteSpace(openResult.ErrorMsg))
{
throw new ServiceException("复核审批失败");
}
//生成文档
if (PS.Config.IsAutoGenerateContracts && (td.TradeStatus == ConsTrade.已平仓 || (td.TradeStatus == ConsTrade.确认成交 && td.HasPartialUnWind == 1)))
{
new TradeContractGenerateService(this).GenerateContractsAsync(new List { td.id });
}
SaveTradeOperationHistory(td, "平仓复核");
if (notrans)
{
trans.Commit();
}
if (td.TradeStatus == ConsTrade.已平仓 || (td.TradeStatus == ConsTrade.确认成交 && td.HasPartialUnWind == 1))
{
if (PS.Config.SalesCommissionCalculation == "公式1")
{
//销售提成
new SalesModule.SalesCommissionDetailDataService(this).CalcuSalesCommissionDetail(tc);
}
if (PS.Config.Company == Configuration.CompanyEnum.招证)
{
new BizLogicZhaoZheng().GenerateZhaoZhengDealNumber(td, tc);
}
if (PS.Config.Company == Configuration.CompanyEnum.物产中大)
{
new BizLogicWCZD().GenerateWCZDNumber(DbContext, td, tc.ValueDate, tc.id);
}
}
return result;
}
else
{
if (td.Warning)
{
new TradeDalService(OptUser).RollbackToBeforeSettle(td, req.ValueDate.Value);
}
result.TradeCash = UnwindTrade(td, req, isFromRecheck);
//配对 平仓(不需要复核且不需要审批的平仓操作)
if (req.IsUnwindPairTrade && !string.IsNullOrEmpty(td.PairTrade))
{
result.HasPairTrade = true;
var pairTradeId = Convert.ToInt32(td.PairTrade);
//var pairTrade = DbContext.trade.Find(pairTradeId);
var pairTrade = new TradeDalService(this).GetTradeOrEodTrade(new[] { pairTradeId }, valueDate, true).FirstOrDefault();
if (pairTrade.Warning)
{
new TradeDalService(OptUser).RollbackToBeforeSettle(pairTrade, valueDate);
}
//配对交易平仓总份额取各自剩余的总份额
req.Notional = pairTrade.Notional;
//UnwindNotional >= Notional代表全部品仓,配对交易的平仓份额为自己剩余的总份额
//UnwindNotional < td.Notional部分平仓,配对的两笔交易部分平仓份额相等,即req.UnwindNotional不变
if (req.UnwindNotional >= pairTrade.Notional)
{
req.UnwindNotional = pairTrade.Notional;
req.UnwindPercentRate = req.Notional > 0 ? (req.UnwindNotional / req.Notional) ?? 0 : 0;
}
try
{
UnwindTrade(pairTrade, req, isFromRecheck);
result.PairTradeUnwindSuccess = true;
SaveTradeOperationHistory(pairTrade, "提交平仓");
}
catch (Exception ex)
{
result.PairTradeUnwindException = ex;
LogFactory.GetLogger("平仓配对交易").Error(ex);
}
}
//生成文档
if (PS.Config.IsAutoGenerateContracts)
{
var tradeIdList = new List { td.id };
if (req.IsUnwindPairTrade && result.HasPairTrade && result.PairTradeUnwindSuccess)
{
tradeIdList.Add(Convert.ToInt32(td.PairTrade));
}
new TradeContractGenerateService(this).GenerateContractsAsync(tradeIdList);
}
SaveTradeOperationHistory(td, "提交平仓");
if (notrans)
{
trans.Commit();
}
return result;
}
}
catch
{
if (notrans)
{
trans.Rollback();
}
throw;
}
finally
{
if (notrans)
{
trans.Dispose();
}
}
}
///
/// 分组了结 主交易平仓复核
///
///
///
///
public void UnwindParentTrade(SaveGroupTradeCashReq req)
{
var parentTradeId = req.trade_cash.TradeId;
var td = DbContext.trade.Find(parentTradeId);
var subTradeIds = DbContext.trade_cash_group_action.Where(x => x.ParentTradeId == parentTradeId && x.Status == "待完成").Select(x => x.TradeId).ToList();
var allTd = DbContext.trade.Where(x => x.id == parentTradeId || subTradeIds.Contains(x.id)).ToList();
using (var trans = BeginTransaction())
{
//平仓复核逻辑验证
if ((valuedateBLL.SystemDate.CloseReCheck == 1) && (td.TradeStatus == ConsTrade.平仓待复核 || td.TradeStatus == ConsTrade.行权待复核))
{
//检查平仓单价
var tc = DbContext.trade_cash.OrderByDescending(x => x.id).FirstOrDefault(dd => dd.TradeId == req.trade_cash.TradeId && (dd.Action == ClientCashInCashOut.系统操作_平仓费 || dd.Action == ClientCashInCashOut.系统操作_行权费) && dd.ValidState == ConsGlobal.InValid && dd.Status == null && !dd.IsDeleted);
if (valuedateBLL.SystemDate.UnwindAmountAngle == 0 && td.BuySell == "卖出")
{
req.trade_cash.Amount *= -1;
}
if (tc.Amount == req.trade_cash.Amount)
{
allTd.ForEach(x =>
{
x.CheckStatus = Convert.ToInt32(TradeCheckEnum.StatusOfUnwind);
x.UnWindDate = tc.ValueDate;
});
DbContext.SaveChanges();
}
else
{
//审核失败
throw new ServiceException("平仓费不一致!复核不通过");
}
}
//存在审批流程时,走审批成功流程(需求②:按交易状态查对应流程)
if (valuedateBLL.SystemDate.CloseReApprove == 1 && TradeProcessCountByCategory(td) > 0)
{
var reqModel = new TradeOpenReqModel
{
tradeId = td.id,
status = "pass",
comments = "平仓复核审批成功",
ignoreMoneyCheck = false,
notNeedOperationHistory = true
};
var openResult = new TradeOpenService(this).UpdateParentTradeProcessLog(reqModel);
if (openResult.RetCode != TradeOpenRetCode.Success && !string.IsNullOrWhiteSpace(openResult.ErrorMsg))
{
throw new ServiceException("复核审批失败");
}
allTd.ForEach(x =>
{
//生成文档
if (PS.Config.IsAutoGenerateContracts && (x.TradeStatus == ConsTrade.已平仓 || (x.TradeStatus == ConsTrade.确认成交 && x.HasPartialUnWind == 1)))
{
new TradeContractGenerateService(this).GenerateContractsAsync(new List { x.id });
}
});
}
else
{
td.IsApproval = false;//复核完成将审核重置
td.TradeOldStatus = td.TradeStatus;
if (req.trade_cash.UnwindType == "全部平仓")
{
td.TradeStatus = "已平仓";
}
else if (req.trade_cash.UnwindType == "部分平仓" || req.trade_cash.UnwindType == "部分提前行权")
{
td.TradeStatus = "确认成交";
}
else if (req.trade_cash.UnwindType == "全部提前行权" || req.trade_cash.UnwindType == "到期行权")
{
td.TradeStatus = "已执行";
}
else if (req.trade_cash.UnwindType == "到期")
{
td.TradeStatus = "已到期";
}
var tradeCashGroupActions = DbContext.trade_cash_group_action.Where(x => x.ParentTradeId == td.id && x.Status == "待完成");
var parentTradeCashId = tradeCashGroupActions.FirstOrDefault().ParentTradeCashId;
var parentTradeCash = DbContext.trade_cash.Find(parentTradeCashId);
parentTradeCash.ValidState = ConsGlobal.Valid;
//设置成开户状态,写日志
td.CheckTradeUpdate = Convert.ToInt32(TradeCheckEnum.StatusOfNew);
td.OptId = UserId;
td.OptName = UserName;
td.OptDate = OptDate;
td.TradeAmount -= (parentTradeCash.UnwindTradeAmount ?? 0);
td.Notional -= (parentTradeCash.UnwindNotional ?? 0);
td.StockEqvNotional -= (td.OriginalStockEqvNotional * parentTradeCash.UnwindPercentRate ?? 0);
td.UnWindNotional = parentTradeCash.UnwindNotional;
td.UnWindDate = parentTradeCash.ValueDate;
td.FinalPrice = parentTradeCash.FinalPrice;
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
req.childTradeCashs.ForEach(x =>
{
var tradeCashReq = new TradeCashReq()
{
ValueDate = req.trade_cash.ValueDate,
TradeId = x.TradeId,
TradeAmount = x.TradeAmount,
Notional = x.Notional,
UnwindFee = x.Amount,
Amount = x.Amount,
UnwindTradeAmount = x.UnwindTradeAmount,
UnwindNotional = (x.UnwindTradeAmount ?? 0) * underlying.CountRatio,
UnwindPercentRate = x.UnwindPercentRate ?? 0,
UnwindStockEqvNotional = x.UnwindStockEqvNotional,
CallPut = x.OptionType,
ExceciseType = "现金",
FinalPrice = req.trade_cash.FinalPrice,
UnwindType = req.trade_cash.UnwindType
};
if (req.trade_cash.UnwindType.Contains("到期"))
{
new TradeCashService(this).ExecutionTradeCash(tradeCashReq);
}
else
{
var subTrade = allTd.FirstOrDefault(y => y.id == x.TradeId);
UnwindTrade(subTrade, null, true);
}
});
//存黑箱主交易ClientCashInCashOut需要赋值0
//TradeCash在下面FinishGroupTradeCash里会根据子交易重新统计赋值
parentTradeCash.Amount = 0;
new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, parentTradeCash, parentTradeCash.ValueDate);
DbContext.SaveChanges();
FinishGroupTradeCash(req.trade_cash.id);//只有复核,无审批,直接将group_action变为已完成
}
trans.Commit();
}
}
///
///
///
public TradeUnwindResultModel ApplyUnwindSwapTrade(TradeCashReq req)
{
var td = DbContext.trade.Find(req.TradeId);
//平仓时如果盈亏为正,则以换汇买价结算,如果盈亏为负,则以换汇卖价结算(客户方向,和TradeCashReq方向相反)
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, req.ValueDate.Value
, seekPreday: true, currencyRateType: req.Amount < 0 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
req.QuoteUnwindFee = req.UnwindFee;
var getQuoteInitialAmount = req.trade_cash_swap.GetInitialAmount;
var payQuoteInitialAmount = req.trade_cash_swap.PayInitialAmount;
var getQuoteExtraAmount = req.trade_cash_swap.GetExtraAmount;
var payQuoteExtraAmount = req.trade_cash_swap.PayExtraAmount;
var getQuoteCostFee = req.trade_cash_swap.GetCostFee;
var payQuoteCostFee = req.trade_cash_swap.PayCostFee;
req.Amount *= currencyRate;
req.UnwindFee *= currencyRate;
req.InitialAmount *= currencyRate;
req.ExtraAmount *= currencyRate;
req.trade_cash_swap.GetAmount *= currencyRate;
req.trade_cash_swap.GetInitialAmount *= currencyRate;
req.trade_cash_swap.GetExtraAmount *= currencyRate;
req.trade_cash_swap.GetCostFee *= currencyRate;
req.trade_cash_swap.PayAmount *= currencyRate;
req.trade_cash_swap.PayInitialAmount *= currencyRate;
req.trade_cash_swap.PayExtraAmount *= currencyRate;
req.trade_cash_swap.PayCostFee *= currencyRate;
req.UnwindPercentRate /= 100;
if (td.StockEqvNotional / td.OriginalStockEqvNotional - req.UnwindPercentRate <= 1e-5)
{
req.UnwindType = "全部平仓";
req.UnwindPercentRate = td.OriginalStockEqvNotional > 0 ? td.StockEqvNotional / td.OriginalStockEqvNotional.Value : 0;
}
req.UnwindNotional = (td.OriginalNotional * req.UnwindPercentRate) ?? 0;
req.Notional = td.Notional;//前端传回来的数量小数位不足,所以这里要重新赋值,保证不会有精度损失;
req.TradeAmount = td.TradeAmount;
if (req.UnwindPercentRate <= 0)
{
throw new Exception("平仓比例不合理");
}
var result = new TradeUnwindResultModel(td);
//增加现金交割交易记录
req.ValidState = ConsGlobal.InValid;
var tc = CloseTrade_TradeCashSave(td, req, false, false, req.UnwindType != "部分平仓");
var tradeCash = DbContext.trade_cash.Where(y => y.TradeId == td.id && y.Action == "系统操作-互换" && y.ValidState != "InValid" && !y.IsDeleted && y.ValueDate <= tc.ValueDate).OrderByDescending(y => y.id).FirstOrDefault();
var tradeCashSwap = tradeCash == null ? null : DbContext.trade_cash_swap.FirstOrDefault(x => x.TradeCashId == tradeCash.id);
tc.StartDate = tradeCash?.ValueDate ?? td.StartDate.Value;
tc.ExerciseWay = TradeCashExerciseWayEnum.提前终止行权;
tc.CurrencyRate = currencyRate;
var trade_swap = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == tc.TradeId);
tc.FinalPrice = trade_swap.IsGetFloatingProfit ? req.trade_cash_swap.GetFinalPrice : req.trade_cash_swap.PayFinalPrice;
var hasTradeProcess = HasTradeProcess();
CloseReCheck_SetTrade(td.id, false, hasTradeProcess);
var trade_cash_swap = req.trade_cash_swap;
trade_cash_swap.StartDate = tc.StartDate;
trade_cash_swap.GetStartPrice = tradeCashSwap?.GetFinalPrice ?? trade_swap.GetSpotPrice;
trade_cash_swap.PayStartPrice = tradeCashSwap?.PayFinalPrice ?? trade_swap.PaySpotPrice;
trade_cash_swap.TradeId = tc.TradeId;
trade_cash_swap.TradeCashId = tc.id;
trade_cash_swap.OptId = tc.OptId;
trade_cash_swap.OptName = tc.OptName;
trade_cash_swap.OptDate = DateTime.Now;
DbContext.trade_cash_swap.Add(trade_cash_swap);
var tcdGetInitialAmount = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = trade_cash_swap.GetInitialAmount,
QuoteAmount = getQuoteInitialAmount,
ValueDate = tc.ValueDate,
IsForGet = true,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.浮动收益.ToString()
};
DbContext.trade_cash_detail.Add(tcdGetInitialAmount);
var tcdGetExtraAmount = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = trade_cash_swap.GetExtraAmount,
QuoteAmount = getQuoteExtraAmount,
ValueDate = tc.ValueDate,
IsForGet = true,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.利息.ToString()
};
DbContext.trade_cash_detail.Add(tcdGetExtraAmount);
var tcdGetCostFee = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = trade_cash_swap.GetCostFee,
QuoteAmount = getQuoteCostFee,
ValueDate = tc.ValueDate,
IsForGet = true,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.了结手续费.ToString()
};
DbContext.trade_cash_detail.Add(tcdGetCostFee);
var tcdPayInitialAmount = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = -trade_cash_swap.PayInitialAmount,
QuoteAmount = -payQuoteInitialAmount,
ValueDate = tc.ValueDate,
IsForGet = false,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.浮动收益.ToString()
};
DbContext.trade_cash_detail.Add(tcdPayInitialAmount);
var tcdPayExtraAmount = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = -trade_cash_swap.PayExtraAmount,
QuoteAmount = -payQuoteExtraAmount,
ValueDate = tc.ValueDate,
IsForGet = false,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.利息.ToString()
};
DbContext.trade_cash_detail.Add(tcdPayExtraAmount);
var tcdPayCostFee = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = -trade_cash_swap.PayCostFee,
QuoteAmount = -payQuoteCostFee,
ValueDate = tc.ValueDate,
IsForGet = false,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.了结手续费.ToString()
};
DbContext.trade_cash_detail.Add(tcdPayCostFee);
DbContext.SaveChanges();
SaveTradeOperationHistory(td, "提交平仓");
return result;
}
///
///
///
public TradeUnwindResultModel ApproveUnwindSwapTrade(trade td)
{
var result = new TradeUnwindResultModel(td);
//增加现金交割交易记录
var tc = CloseTrade_TradeCashSave(td, null, true, false);
var groupAction = DbContext.trade_cash_group_action.FirstOrDefault(x => x.TradeId == td.id && x.Status != "已完成");
if (groupAction != null)
{
groupAction.Status = "已完成";
tc.ParentTradeCashId = groupAction.ParentTradeCashId;
tc.ParentTradeId = groupAction.ParentTradeId;
}
tc.ValidState = "Valid";
tc.ExerciseWay = TradeCashExerciseWayEnum.提前终止行权;
//加入平仓份额和平仓日期
if (tc.UnwindType == "全部平仓")
{
td.TradeStatus = ConsTrade.已平仓;
tc.IsLastAction = true;
}
else
{
td.TradeStatus = ConsTrade.确认成交;
td.HasPartialUnWind = 1;
tc.IsLastAction = false;
}
td.UnWindDate = tc.ValueDate;
td.StockEqvNotional -= (td.OriginalStockEqvNotional ?? 0) * (tc.UnwindPercentRate ?? 0);
td.Notional -= (td.OriginalNotional ?? 0) * (tc.UnwindPercentRate ?? 0);
//给TradeAmount赋对应的值
var CountRatio = UnderlyingDataProvider.GetCountRatio(td.UnderlyingCode);
td.TradeAmount = td.Notional / CountRatio;
td.UnWindNotional = tc.UnwindNotional;
//增加出入金记录
new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, tc, tc.ValueDate);
if (td.ParentTradeId > 0)
{
var parentTrade = DbContext.trade.Find(td.ParentTradeId);
if (parentTrade != null)
{
parentTrade.StockEqvNotional -= (td.OriginalStockEqvNotional ?? 0) * (tc.UnwindPercentRate ?? 0);
if (parentTrade.StockEqvNotional <= 0)
{
parentTrade.TradeStatus = "已平仓";
}
var tradeSwapDetail = DbContext.trade_swap_detail.FirstOrDefault(x => x.TradeId == parentTrade.id && x.ChildTradeId == td.id);
if (tradeSwapDetail != null)
{
tradeSwapDetail.Notional = td.Notional;
}
}
}
DbContext.SaveChanges();
//删除E/Bod数据
var delTcIds = tc.Action == ClientCashInCashOut.系统操作_互换 ? GetRemovedTcIdsForSwapSettlement(td.id, tc) : null;
RemoveEodTradeAndFutureInfo(saveChanges: true, tradeId: td.id, removeStartDate: tc.ValueDate, tradeCashIds: delTcIds);
return result;
}
///
/// 互换交易平仓
///
///
/// 请求是否来自前端用户
///
public TradeUnwindResultModel UnwindSwapTrade(TradeCashReq req)
{
var trade = DbContext.trade.Find(req.TradeId);
//平仓时如果盈亏为正,则以换汇买价结算,如果盈亏为负,则以换汇卖价结算(客户方向,和TradeCashReq方向相反)
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(trade.QuoteCurrency, trade.SettlementCurrency, req.ValueDate.Value
, seekPreday: true, currencyRateType: req.Amount < 0 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
req.QuoteUnwindFee = req.UnwindFee;
var getQuoteInitialAmount = req.trade_cash_swap.GetInitialAmount;
var payQuoteInitialAmount = req.trade_cash_swap.PayInitialAmount;
var getQuoteExtraAmount = req.trade_cash_swap.GetExtraAmount;
var payQuoteExtraAmount = req.trade_cash_swap.PayExtraAmount;
var getQuoteCostFee = req.trade_cash_swap.GetCostFee;
var payQuoteCostFee = req.trade_cash_swap.PayCostFee;
req.Amount *= currencyRate;
req.UnwindFee *= currencyRate;
req.InitialAmount *= currencyRate;
req.ExtraAmount *= currencyRate;
req.trade_cash_swap.GetAmount *= currencyRate;
req.trade_cash_swap.GetInitialAmount *= currencyRate;
req.trade_cash_swap.GetExtraAmount *= currencyRate;
req.trade_cash_swap.GetCostFee *= currencyRate;
req.trade_cash_swap.PayAmount *= currencyRate;
req.trade_cash_swap.PayInitialAmount *= currencyRate;
req.trade_cash_swap.PayExtraAmount *= currencyRate;
req.trade_cash_swap.PayCostFee *= currencyRate;
req.UnwindPercentRate /= 100;
var td = DbContext.trade.Find(req.TradeId);
if (td.StockEqvNotional / td.OriginalStockEqvNotional - req.UnwindPercentRate <= 1e-5)
{
req.UnwindType = "全部平仓";
req.UnwindPercentRate = td.OriginalStockEqvNotional > 0 ? td.StockEqvNotional / td.OriginalStockEqvNotional.Value : 0;
}
req.UnwindNotional = (td.OriginalNotional * req.UnwindPercentRate) ?? 0;
req.Notional = td.Notional;//前端传回来的数量小数位不足,所以这里要重新赋值,保证不会有精度损失;
req.TradeAmount = td.TradeAmount;
if (req.UnwindPercentRate <= 0)
{
throw new Exception("平仓比例不合理");
}
var result = new TradeUnwindResultModel(td);
//增加现金交割交易记录
var tc = CloseTrade_TradeCashSave(td, req, false, false, req.UnwindType != "部分平仓");
var groupAction = DbContext.trade_cash_group_action.FirstOrDefault(x => x.TradeId == td.id && x.Status != "已完成");
if (groupAction != null)
{
groupAction.Status = "已完成";
tc.ParentTradeCashId = groupAction.ParentTradeCashId;
tc.ParentTradeId = groupAction.ParentTradeId;
}
var tradeCash = DbContext.trade_cash.Where(y => y.TradeId == td.id && y.Action == "系统操作-互换" && y.ValidState != "InValid" && !y.IsDeleted && y.ValueDate <= tc.ValueDate).OrderByDescending(y => y.id).FirstOrDefault();
var tradeCashSwap = tradeCash == null ? null : DbContext.trade_cash_swap.FirstOrDefault(x => x.TradeCashId == tradeCash.id);
tc.StartDate = tradeCash?.ValueDate ?? td.StartDate.Value;
tc.ValidState = "Valid";
tc.ExerciseWay = TradeCashExerciseWayEnum.提前终止行权;
tc.CurrencyRate = currencyRate;
var trade_swap = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == tc.TradeId);
tc.FinalPrice = trade_swap.IsGetFloatingProfit ? req.trade_cash_swap.GetFinalPrice : req.trade_cash_swap.PayFinalPrice;
//加入平仓份额和平仓日期
if (req.UnwindType == "全部平仓")
{
td.TradeStatus = "已平仓";
}
else
{
td.HasPartialUnWind = 1;
}
td.UnWindDate = tc.ValueDate;
td.StockEqvNotional -= (td.OriginalStockEqvNotional ?? 0) * req.UnwindPercentRate;
td.Notional -= (td.OriginalNotional ?? 0) * req.UnwindPercentRate;
td.UnWindNotional = tc.UnwindNotional;
//给TradeAmount赋对应的值
var CountRatio = UnderlyingDataProvider.GetCountRatio(td.UnderlyingCode);
td.TradeAmount = td.Notional / CountRatio;
//增加出入金记录
new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, tc, tc.ValueDate);
td.OptId = (int)tc.OptId;
td.OptName = tc.OptName;
td.OptDate = DateTime.Now;
var trade_cash_swap = req.trade_cash_swap;
trade_cash_swap.StartDate = tc.StartDate;
trade_cash_swap.GetStartPrice = tradeCashSwap?.GetFinalPrice ?? trade_swap.GetSpotPrice;
trade_cash_swap.PayStartPrice = tradeCashSwap?.PayFinalPrice ?? trade_swap.PaySpotPrice;
trade_cash_swap.TradeId = tc.TradeId;
trade_cash_swap.TradeCashId = tc.id;
trade_cash_swap.OptId = tc.OptId;
trade_cash_swap.OptName = tc.OptName;
trade_cash_swap.OptDate = DateTime.Now;
DbContext.trade_cash_swap.Add(trade_cash_swap);
var tcdGetInitialAmount = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = trade_cash_swap.GetInitialAmount,
QuoteAmount = getQuoteInitialAmount,
ValueDate = tc.ValueDate,
IsForGet = true,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.浮动收益.ToString()
};
DbContext.trade_cash_detail.Add(tcdGetInitialAmount);
var tcdGetExtraAmount = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = trade_cash_swap.GetExtraAmount,
QuoteAmount = getQuoteExtraAmount,
ValueDate = tc.ValueDate,
IsForGet = true,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.利息.ToString()
};
DbContext.trade_cash_detail.Add(tcdGetExtraAmount);
var tcdGetCostFee = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = trade_cash_swap.GetCostFee,
QuoteAmount = getQuoteCostFee,
ValueDate = tc.ValueDate,
IsForGet = true,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.了结手续费.ToString()
};
DbContext.trade_cash_detail.Add(tcdGetCostFee);
var tcdPayInitialAmount = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = -trade_cash_swap.PayInitialAmount,
QuoteAmount = -payQuoteInitialAmount,
ValueDate = tc.ValueDate,
IsForGet = false,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.浮动收益.ToString()
};
DbContext.trade_cash_detail.Add(tcdPayInitialAmount);
var tcdPayExtraAmount = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = -trade_cash_swap.PayExtraAmount,
QuoteAmount = -payQuoteExtraAmount,
ValueDate = tc.ValueDate,
IsForGet = false,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.利息.ToString()
};
DbContext.trade_cash_detail.Add(tcdPayExtraAmount);
var tcdPayCostFee = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = -trade_cash_swap.PayCostFee,
QuoteAmount = -payQuoteCostFee,
ValueDate = tc.ValueDate,
IsForGet = false,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.了结手续费.ToString()
};
DbContext.trade_cash_detail.Add(tcdPayCostFee);
if (td.ParentTradeId > 0)
{
var parentTrade = DbContext.trade.Find(td.ParentTradeId);
if (parentTrade != null)
{
parentTrade.StockEqvNotional -= (td.OriginalStockEqvNotional ?? 0) * req.UnwindPercentRate;
if (parentTrade.StockEqvNotional <= 0)
{
parentTrade.TradeStatus = "已平仓";
}
var tradeSwapDetail = DbContext.trade_swap_detail.FirstOrDefault(x => x.TradeId == parentTrade.id && x.ChildTradeId == td.id);
if (tradeSwapDetail != null)
{
tradeSwapDetail.Notional = td.Notional;
}
}
}
#region 补充期末价格,对其部分重新赋值
trade_swap.GetFinalPrice = trade_cash_swap.GetFinalPrice;
trade_swap.PayFinalPrice = trade_cash_swap.PayFinalPrice;
#endregion
DbContext.SaveChanges();
SaveTradeOperationHistory(td, "提交平仓");
//删除E/Bod数据
RemoveEodTradeAndFutureInfo(true, td.id, tc.ValueDate);
return result;
}
///
/// 提交互换收益结算申请
///
public TradeUnwindResultModel ApplySwapTradeSettlement(TradeCashReq req)
{
var trade = DbContext.trade.Find(req.TradeId);
//平仓时如果盈亏为正,则以换汇买价结算,如果盈亏为负,则以换汇卖价结算(客户方向,和TradeCashReq方向相反)
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(trade.QuoteCurrency, trade.SettlementCurrency, req.ValueDate.Value
, currencyRateType: req.Amount < 0 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
req.QuoteUnwindFee = req.UnwindFee;
var getQuoteInitialAmount = req.trade_cash_swap.GetInitialAmount;
var payQuoteInitialAmount = req.trade_cash_swap.PayInitialAmount;
var getQuoteExtraAmount = req.trade_cash_swap.GetExtraAmount;
var payQuoteExtraAmount = req.trade_cash_swap.PayExtraAmount;
var getQuoteCostFee = req.trade_cash_swap.GetCostFee;
var payQuoteCostFee = req.trade_cash_swap.PayCostFee;
req.UnwindFee *= currencyRate;
req.Amount *= currencyRate;
req.InitialAmount *= currencyRate;
req.ExtraAmount *= currencyRate;
req.trade_cash_swap.GetAmount *= currencyRate;
req.trade_cash_swap.GetInitialAmount *= currencyRate;
req.trade_cash_swap.GetExtraAmount *= currencyRate;
req.trade_cash_swap.GetCostFee *= currencyRate;
req.trade_cash_swap.PayAmount *= currencyRate;
req.trade_cash_swap.PayInitialAmount *= currencyRate;
req.trade_cash_swap.PayExtraAmount *= currencyRate;
req.trade_cash_swap.PayCostFee *= currencyRate;
req.UnwindPercentRate /= 100;
var td = DbContext.trade.Find(req.TradeId);
req.Notional = td.Notional;//前端传回来的数量小数位不足,所以这里要重新赋值,保证不会有精度损失;
req.TradeAmount = td.TradeAmount;
var result = new TradeUnwindResultModel(td);
//增加现金交割交易记录
req.ValidState = ConsGlobal.InValid;
var tc = CloseTrade_TradeCashSave(td, req, false, false);
var tradeCash = DbContext.trade_cash.Where(y => y.TradeId == td.id && y.Action == "系统操作-互换" && y.ValidState != "InValid" && !y.IsDeleted && y.ValueDate <= tc.ValueDate).OrderByDescending(y => y.id).FirstOrDefault();
var tradeCashSwap = tradeCash == null ? null : DbContext.trade_cash_swap.FirstOrDefault(x => x.TradeCashId == tradeCash.id);
tc.StartDate = tradeCash?.ValueDate ?? td.StartDate.Value;
tc.Action = ClientCashInCashOut.系统操作_互换;
tc.UnwindType = null;
tc.CurrencyRate = currencyRate;
var trade_swap = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == tc.TradeId);
tc.FinalPrice = trade_swap.IsGetFloatingProfit ? req.trade_cash_swap.GetFinalPrice : req.trade_cash_swap.PayFinalPrice;
if (td.ExerciseDate > req.ValueDate)
{
tc.UnwindNotional = 0;
tc.UnwindTradeAmount = 0;
tc.UnwindPercentRate = 0;
tc.ExerciseWay = TradeCashExerciseWayEnum.提前终止行权;
tc.IsLastAction = false;
}
else
{
tc.ExerciseWay = TradeCashExerciseWayEnum.到期行权;
tc.IsLastAction = true;
if (td.ExerciseDate == req.ValueDate)
{
tc.ValueDate = td.SettlementDate ?? td.ExerciseDate.Value;
tc.HappenedDate = td.ExerciseDate;
tc.HappenedDate = QdpCalendarHelper.GetNonHoliday(tc.HappenedDate.Value);
}
}
var hasTradeProcess = HasTradeProcess();
CloseReCheck_SetTrade(td.id, true, hasTradeProcess);
var lastGetFinalPrice = tradeCashSwap?.GetFinalPrice;
var lastPayFinalPrice = tradeCashSwap?.PayFinalPrice;
var trade_cash_swap = req.trade_cash_swap;
trade_cash_swap.StartDate = tc.StartDate;
trade_cash_swap.GetStartPrice = lastGetFinalPrice ?? trade_swap.GetSpotPrice;
trade_cash_swap.PayStartPrice = lastPayFinalPrice ?? trade_swap.PaySpotPrice;
trade_cash_swap.TradeId = tc.TradeId;
trade_cash_swap.TradeCashId = tc.id;
trade_cash_swap.OptId = tc.OptId;
trade_cash_swap.OptName = tc.OptName;
trade_cash_swap.OptDate = DateTime.Now;
DbContext.trade_cash_swap.Add(trade_cash_swap);
var tcdGetInitialAmount = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = trade_cash_swap.GetInitialAmount,
QuoteAmount = getQuoteInitialAmount,
ValueDate = tc.ValueDate,
IsForGet = true,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.浮动收益.ToString()
};
DbContext.trade_cash_detail.Add(tcdGetInitialAmount);
var tcdGetExtraAmount = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = trade_cash_swap.GetExtraAmount,
QuoteAmount = getQuoteExtraAmount,
ValueDate = tc.ValueDate,
IsForGet = true,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.利息.ToString()
};
DbContext.trade_cash_detail.Add(tcdGetExtraAmount);
var tcdGetCostFee = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = trade_cash_swap.GetCostFee,
QuoteAmount = getQuoteCostFee,
ValueDate = tc.ValueDate,
IsForGet = true,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.了结手续费.ToString()
};
DbContext.trade_cash_detail.Add(tcdGetCostFee);
var tcdPayInitialAmount = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = -trade_cash_swap.PayInitialAmount,
QuoteAmount = -payQuoteInitialAmount,
ValueDate = tc.ValueDate,
IsForGet = false,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.浮动收益.ToString()
};
DbContext.trade_cash_detail.Add(tcdPayInitialAmount);
var tcdPayExtraAmount = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = -trade_cash_swap.PayExtraAmount,
QuoteAmount = -payQuoteExtraAmount,
ValueDate = tc.ValueDate,
IsForGet = false,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.利息.ToString()
};
DbContext.trade_cash_detail.Add(tcdPayExtraAmount);
var tcdPayCostFee = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = -trade_cash_swap.PayCostFee,
QuoteAmount = -payQuoteCostFee,
ValueDate = tc.ValueDate,
IsForGet = false,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.了结手续费.ToString()
};
DbContext.trade_cash_detail.Add(tcdPayCostFee);
DbContext.SaveChanges();
SaveTradeOperationHistory(td, "提交互换");
return result;
}
///
/// 审批通过互换交易申请
///
public TradeUnwindResultModel ApproveSwapTrade(trade td)
{
var result = new TradeUnwindResultModel(td);
//增加现金交割交易记录
var tc = CloseTrade_TradeCashSave(td, null, true, false);
var groupAction = DbContext.trade_cash_group_action.FirstOrDefault(x => x.TradeId == td.id && x.Status != "已完成");
if (groupAction != null)
{
groupAction.Status = "已完成";
tc.ParentTradeCashId = groupAction.ParentTradeCashId;
tc.ParentTradeId = groupAction.ParentTradeId;
}
tc.ValidState = "Valid";
//加入平仓份额和平仓日期
td.UnWindDate = tc.ValueDate;
if (td.ExerciseDate > tc.ValueDate)
{
td.TradeStatus = ConsTrade.确认成交;
tc.IsLastAction = false;
}
else
{
td.TradeStatus = ConsTrade.已到期;
td.Notional = 0;
td.StockEqvNotional = 0;
td.TradeAmount = 0;
tc.IsLastAction = true;
}
var tradeCashSwap = DbContext.trade_cash_swap.FirstOrDefault(x => x.TradeCashId == tc.id);
if (tradeCashSwap != null)
{
var trade_swap = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == tc.TradeId);
trade_swap.GetFinalPrice = tradeCashSwap.GetFinalPrice;
trade_swap.PayFinalPrice = tradeCashSwap.PayFinalPrice;
tc.FinalPrice = trade_swap.IsGetFloatingProfit ? tradeCashSwap.GetFinalPrice : tradeCashSwap.PayFinalPrice;
}
//增加出入金记录
var ee = new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, tc, tc.ValueDate);
DbContext.SaveChanges();
//删除E/Bod数据
var delTcIds = tc.Action == ClientCashInCashOut.系统操作_互换 ? GetRemovedTcIdsForSwapSettlement(td.id, tc) : null;
RemoveEodTradeAndFutureInfo(saveChanges: true, tradeId: td.id, removeStartDate: tc.ValueDate, tradeCashIds: delTcIds);
return result;
}
///
/// 获取互换收益结算执行后需要删除的后续trade cash ids
///
private IEnumerable GetRemovedTcIdsForSwapSettlement(int tradeId, trade_cash currentTc)
{
var query = from tc in DbContext.trade_cash
where tc.TradeId == tradeId
&& tc.Action == ClientCashInCashOut.系统操作_互换
&& tc.ValueDate > currentTc.ValueDate && tc.id != currentTc.id
&& (tc.HappenedDate == null || tc.HappenedDate > currentTc.ValueDate)
&& tc.ValidState != ConsGlobal.InValid && !tc.IsDeleted
select tc.id;
var ids = query.ToArray();
return ids.Any() ? ids : new[] { 0 };
}
public TradeUnwindResultModel SwapTrade(TradeCashReq req)
{
var trade = DbContext.trade.Find(req.TradeId);
//平仓时如果盈亏为正,则以换汇买价结算,如果盈亏为负,则以换汇卖价结算(客户方向,和TradeCashReq方向相反)
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(trade.QuoteCurrency, trade.SettlementCurrency, req.ValueDate.Value
, currencyRateType: req.Amount < 0 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
req.QuoteUnwindFee = req.UnwindFee;
var getQuoteInitialAmount = req.trade_cash_swap.GetInitialAmount;
var payQuoteInitialAmount = req.trade_cash_swap.PayInitialAmount;
var getQuoteExtraAmount = req.trade_cash_swap.GetExtraAmount;
var payQuoteExtraAmount = req.trade_cash_swap.PayExtraAmount;
var getQuoteCostFee = req.trade_cash_swap.GetCostFee;
var payQuoteCostFee = req.trade_cash_swap.PayCostFee;
req.UnwindFee *= currencyRate;
req.Amount *= currencyRate;
req.InitialAmount *= currencyRate;
req.ExtraAmount *= currencyRate;
req.trade_cash_swap.GetAmount *= currencyRate;
req.trade_cash_swap.GetInitialAmount *= currencyRate;
req.trade_cash_swap.GetExtraAmount *= currencyRate;
req.trade_cash_swap.PayAmount *= currencyRate;
req.trade_cash_swap.PayInitialAmount *= currencyRate;
req.trade_cash_swap.PayExtraAmount *= currencyRate;
req.UnwindPercentRate /= 100;
var td = DbContext.trade.Find(req.TradeId);
req.Notional = td.Notional;//前端传回来的数量小数位不足,所以这里要重新赋值,保证不会有精度损失;
req.TradeAmount = td.TradeAmount;
var result = new TradeUnwindResultModel(td);
//增加现金交割交易记录
var tc = CloseTrade_TradeCashSave(td, req, false, false);
var groupAction = DbContext.trade_cash_group_action.FirstOrDefault(x => x.TradeId == td.id && x.Status != "已完成");
if (groupAction != null)
{
groupAction.Status = "已完成";
tc.ParentTradeCashId = groupAction.ParentTradeCashId;
tc.ParentTradeId = groupAction.ParentTradeId;
}
var tradeCash = DbContext.trade_cash.Where(y => y.TradeId == td.id && y.Action == "系统操作-互换" && y.ValidState != "InValid" && !y.IsDeleted && y.ValueDate <= tc.ValueDate).OrderByDescending(y => y.id).FirstOrDefault();
var tradeCashSwap = tradeCash == null ? null : DbContext.trade_cash_swap.FirstOrDefault(x => x.TradeCashId == tradeCash.id);
tc.StartDate = tradeCash?.ValueDate ?? td.StartDate.Value;
tc.ValidState = "Valid";
tc.Action = ClientCashInCashOut.系统操作_互换;
tc.CurrencyRate = currencyRate;
tc.UnwindType = null;
var trade_swap = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == tc.TradeId);
tc.FinalPrice = trade_swap.IsGetFloatingProfit ? req.trade_cash_swap.GetFinalPrice : req.trade_cash_swap.PayFinalPrice;
if (td.ExerciseDate > req.ValueDate)
{
tc.UnwindNotional = 0;
tc.UnwindTradeAmount = 0;
tc.UnwindPercentRate = 0;
tc.ExerciseWay = TradeCashExerciseWayEnum.提前终止行权;
tc.IsLastAction = false;
}
else
{
tc.ExerciseWay = TradeCashExerciseWayEnum.到期行权;
//执行到期时,发生日期记为到期日
tc.HappenedDate = tc.ValueDate;
if (tc.ValueDate == td.ExerciseDate)
{
//非延期交易,如果有结算日期,资金记在结算日
tc.ValueDate = td.SettlementDate ?? tc.ValueDate;
}
tc.UnwindNotional = td.Notional;
tc.UnwindTradeAmount = td.TradeAmount;
tc.UnwindPercentRate = td.StockEqvNotional / td.OriginalStockEqvNotional;
td.Notional = 0;
td.StockEqvNotional = 0;
td.TradeAmount = 0;
td.TradeStatus = "已到期";
tc.IsLastAction = true;
if (td.ParentTradeId > 0)
{
var parentTrade = DbContext.trade.Find(td.ParentTradeId);
if (parentTrade != null)
{
parentTrade.StockEqvNotional -= (td.OriginalStockEqvNotional ?? 0) * (tc.UnwindPercentRate ?? 0);
if (parentTrade.StockEqvNotional <= 0)
{
parentTrade.TradeStatus = "已平仓";
}
}
}
}
//加入平仓份额和平仓日期
td.UnWindDate = tc.ValueDate;
var lastGetFinalPrice = tradeCashSwap?.GetFinalPrice;
var lastPayFinalPrice = tradeCashSwap?.PayFinalPrice;
trade_swap.GetFinalPrice = req.trade_cash_swap.GetFinalPrice;
trade_swap.PayFinalPrice = req.trade_cash_swap.PayFinalPrice;
//增加出入金记录
var ee = new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, tc, tc.ValueDate);
var trade_cash_swap = req.trade_cash_swap;
trade_cash_swap.StartDate = tc.StartDate;
trade_cash_swap.GetStartPrice = lastGetFinalPrice ?? trade_swap.GetSpotPrice;
trade_cash_swap.PayStartPrice = lastPayFinalPrice ?? trade_swap.PaySpotPrice;
trade_cash_swap.TradeId = tc.TradeId;
trade_cash_swap.TradeCashId = tc.id;
trade_cash_swap.OptId = tc.OptId;
trade_cash_swap.OptName = tc.OptName;
trade_cash_swap.OptDate = DateTime.Now;
DbContext.trade_cash_swap.Add(trade_cash_swap);
var getAmount = trade_cash_swap.GetAmount ?? 0;
var getExtraAmount = trade_cash_swap.GetExtraAmount ?? 0;
var tcdGetInitialAmount = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = trade_cash_swap.GetInitialAmount,
QuoteAmount = getQuoteInitialAmount,
ValueDate = tc.ValueDate,
IsForGet = true,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.浮动收益.ToString()
};
DbContext.trade_cash_detail.Add(tcdGetInitialAmount);
var tcdGetExtraAmount = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = trade_cash_swap.GetExtraAmount,
QuoteAmount = getQuoteExtraAmount,
ValueDate = tc.ValueDate,
IsForGet = true,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.利息.ToString()
};
DbContext.trade_cash_detail.Add(tcdGetExtraAmount);
var tcdGetCostFee = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = trade_cash_swap.GetCostFee,
QuoteAmount = getQuoteCostFee,
ValueDate = tc.ValueDate,
IsForGet = true,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.了结手续费.ToString()
};
DbContext.trade_cash_detail.Add(tcdGetCostFee);
var tcdPayInitialAmount = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = -trade_cash_swap.PayInitialAmount,
QuoteAmount = -payQuoteInitialAmount,
ValueDate = tc.ValueDate,
IsForGet = false,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.浮动收益.ToString()
};
DbContext.trade_cash_detail.Add(tcdPayInitialAmount);
var tcdPayExtraAmount = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = -trade_cash_swap.PayExtraAmount,
QuoteAmount = -payQuoteExtraAmount,
ValueDate = tc.ValueDate,
IsForGet = false,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.利息.ToString()
};
DbContext.trade_cash_detail.Add(tcdPayExtraAmount);
var tcdPayCostFee = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = -trade_cash_swap.PayCostFee,
QuoteAmount = -payQuoteCostFee,
ValueDate = tc.ValueDate,
IsForGet = false,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum.了结手续费.ToString()
};
DbContext.trade_cash_detail.Add(tcdPayCostFee);
DbContext.SaveChanges();
SaveTradeOperationHistory(td, "收益互换");
//删除E/Bod数据
var delTcIds = GetRemovedTcIdsForSwapSettlement(td.id, tc);
RemoveEodTradeAndFutureInfo(saveChanges: true, tradeId: td.id, removeStartDate: tc.ValueDate, tradeCashIds: delTcIds);
return result;
}
///
/// 黑箱交易主交易tradecash保存子交易了结费用加和的值
/// clientcashincashout保存一条0的记录
/// 主要为了解决我们是按照子交易进行结算,但是客户结算报告,又想以主交易来展示主交易资金
///
///
public void SaveGroupTradeCash(SaveGroupTradeCashReq req)
{
if (DbContext.trade_cash.Any(x => x.TradeId == req.trade_cash.TradeId && x.Status == null && x.ValidState != "InValid" && x.Action != "系统操作-期权费" && !x.IsDeleted))
{
throw new Exception("上一次分组了结还未完成,完成后才可以继续后需了结操作");
}
//如果选择的是主交易,则代表所有活着的子交易都参与结算
bool parentTrade = false;
if (req.tradeIds.Count == 1 && req.tradeIds.First() == req.trade_cash.TradeId)
{
parentTrade = true;
req.tradeIds = DbContext.trade.Where(x => x.ValidState != "InValid" && x.ParentTradeId == req.trade_cash.TradeId && x.TradeStatus == "确认成交").Select(x => x.id).ToList();
if (!req.tradeIds.Any())
{
throw new Exception("该分组交易没有可以了结操作的子交易,添加失败");
}
}
var action = req.trade_cash.Action;
var trade_cash = req.trade_cash;
var trade = DbContext.trade.Find(trade_cash.TradeId);
trade_cash.OptId = UserId;
trade_cash.OptName = UserName;
trade_cash.OptDate = DateTime.Now;
trade_cash.ValidState = ConsGlobal.InValid;
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode);
if (trade.IsUsePremiumRate == true)
{
if (trade_cash.IsUnwindStockEqvNotional == true)
{
trade_cash.UnwindPercentRate = trade_cash.UnwindStockEqvNotional / trade.OriginalStockEqvNotional;
}
else
{
trade_cash.UnwindPercentRate = trade_cash.UnwindPercentRate / 100;
}
trade_cash.UnwindNotional = trade.OriginalNotional * trade_cash.UnwindPercentRate;
trade_cash.UnwindTradeAmount = trade_cash.UnwindNotional / underlying.CountRatio;
}
else
{
trade_cash.UnwindNotional = trade_cash.UnwindTradeAmount * underlying.CountRatio;
trade_cash.UnwindPercentRate = trade.OriginalNotional != 0 ? trade_cash.UnwindNotional / trade.OriginalNotional : 0;
}
bool isFromExercise = true;
if (trade_cash.Action == "全部平仓")
{
trade_cash.Action = ClientCashInCashOut.系统操作_平仓费;
trade_cash.IsLastAction = true;
trade_cash.ExerciseWay = "提前终止行权";
trade_cash.UnwindType = "全部平仓";
trade.TradeStatus = "已平仓";
isFromExercise = false;
}
else if (trade_cash.Action == "部分平仓")
{
trade_cash.Action = ClientCashInCashOut.系统操作_平仓费;
trade_cash.IsLastAction = false;
trade_cash.ExerciseWay = "提前终止行权";
trade_cash.UnwindType = "部分平仓";
isFromExercise = false;
if (trade_cash.UnwindNotional > trade.Notional)
{
throw new Exception("部分平仓,平仓数量需要小于剩余数量");
}
}
else if (trade_cash.Action == "部分提前行权")
{
trade_cash.Action = ClientCashInCashOut.系统操作_平仓费;
trade_cash.IsLastAction = false;
trade_cash.ExerciseWay = "提前终止行权";
trade_cash.UnwindType = "部分行权";
if (trade_cash.UnwindNotional >= trade.Notional)
{
throw new Exception("部分行权,行权数量需要小于剩余数量");
}
}
else if (trade_cash.Action == "全部提前行权")
{
trade_cash.Action = ClientCashInCashOut.系统操作_行权费;
trade_cash.IsLastAction = true;
trade_cash.ExerciseWay = "提前终止行权";
trade_cash.UnwindType = "全部行权";
trade.TradeStatus = "已执行";
}
else if (trade_cash.Action == "到期行权")
{
trade_cash.Action = ClientCashInCashOut.系统操作_行权费;
trade_cash.IsLastAction = true;
trade_cash.ExerciseWay = "到期行权";
trade_cash.UnwindType = "到期行权";
trade.TradeStatus = "已执行";
}
else if (trade_cash.Action == "到期")
{
trade_cash.Action = ClientCashInCashOut.系统操作_行权费;
trade_cash.IsLastAction = true;
trade_cash.ExerciseWay = "到期行权";
trade_cash.UnwindType = "到期";
trade.TradeStatus = "已到期";
}
using (var trans = BeginTransaction())
{
if (valuedateBLL.SystemDate.UnwindAmountAngle == 0 && trade.BuySell == "卖出")
{
trade_cash.Amount *= -1;
}
DbContext.trade_cash.Add(trade_cash);
DbContext.SaveChanges();
var hasProcess = DbContext.approvalprocess.Where(t => t.processType == "TradeProcess").Any();
var childTradeId = 0;
req.tradeIds.ForEach(x =>
{
if (x != req.trade_cash.TradeId && x != 0)
{
var groupAction = new trade_cash_group_action()
{
TradeId = x,
ParentTradeId = trade_cash.TradeId,
ParentTradeCashId = trade_cash.id,
Status = "待完成",
OptId = UserId,
OptName = UserName,
OptDate = DateTime.Now
};
if ((valuedateBLL.SystemDate.CloseReCheck == 1 || (valuedateBLL.SystemDate.CloseReApprove == 1 && hasProcess)) && !parentTrade)
{
UpdateTradeApproval(x);
}
childTradeId = x;
DbContext.trade_cash_group_action.Add(groupAction);
}
});
trade.IsApproval = parentTrade && !req.from_group_options_close_start_v1;
if (req.childTradeCashs != null && req.childTradeCashs.Count > 0)
{
SaveGroupChildTradeCashs(req, underlying.CountRatio, hasProcess, trade_cash.id, trade.TradeStatus, trans);
}
if ((valuedateBLL.SystemDate.CloseReCheck == 1 || (valuedateBLL.SystemDate.CloseReApprove == 1 && hasProcess)) && parentTrade)//主交易进审批流
{
new TradeCloseService(this).CloseReCheck_SetTrade(trade.id, isFromExercise, true);
}
else
{
#region---存入ClientCashInCashOut---
var cl = ClientDataQueryService.GetClient(trade.ClientId, true);
var ee = new ClientCashInCashOut
{
Direction = "应收",
Number = UniqueTimeId.GetStr(),
ClientId = cl.id,
ClientNumber = cl.Number,
ClientName = cl.Name,
HappenDate = trade_cash.ValueDate,
State = ClientCashInCashOut.已确认,
OptId = trade_cash.OptId,
OptName = trade_cash.OptName,
OptDate = trade_cash.OptDate,
CreatorId = trade_cash.OptId,
CreatorName = trade_cash.OptName,
CreateDate = trade_cash.OptDate,
TradeId = trade_cash.TradeId,
TradeCashId = trade_cash.id,
Action = trade_cash.Action,
TradeNumber = trade.TradeNumber,
IsGroup = trade.IsGroup
};
DbContext.ClientCashInCashOut.Add(ee);
#endregion
trade.TradeAmount -= (trade_cash.UnwindTradeAmount ?? 0);
trade.Notional -= (trade_cash.UnwindNotional ?? 0);
trade.StockEqvNotional -= (trade.OriginalStockEqvNotional * trade_cash.UnwindPercentRate ?? 0);
trade.UnWindNotional = trade_cash.UnwindNotional;
trade.UnWindDate = trade_cash.ValueDate;
trade.FinalPrice = req.trade_cash.FinalPrice;
trade_cash.ValidState = ConsGlobal.Valid;
if (parentTrade) //无复核无审批,group_action直接完成
{
FinishGroupTradeCash(trade_cash.id);
}
}
AddTradeOperationHistoryAndSetParentTradeInfo(false, trade, action);
//删除E/Bod数据
RemoveEodTradeAndFutureInfo(false, trade.id, req.trade_cash.ValueDate);
DbContext.SaveChanges();
trans.Commit();
}
}
///
/// 修改交易分组了结 标识
///
///
private void UpdateTradeApproval(int tradeId)
{
var trade = DbContext.trade.Find(tradeId);
trade.IsApproval = true;
}
public void SaveGroupChildTradeCashs(SaveGroupTradeCashReq req, int countRatio, bool hasProcess, int parentTradeCashId, string tradeStatus, IDbContextTransaction trans)
{
req.childTradeCashs.ForEach(x =>
{
trade td = DbContext.trade.Where(l => l.TraderId == x.id).FirstOrDefault();
var unwindPrice = x.UnwindTradeAmount == 0 ? 0 : x.Amount / x.UnwindTradeAmount;
var tradeCashReq = new TradeCashReq()
{
ValueDate = req.trade_cash.ValueDate,
TradeId = x.TradeId,
TradeAmount = x.TradeAmount,
Notional = x.Notional,
UnwindFee = x.Amount,
Amount = x.Amount,
UnwindPrice = unwindPrice,
UnwindPricePercentRate = TradeHelper.GetPremiumRateByTradeSinglePrice(unwindPrice, td?.SpotPrice),
UnwindTradeAmount = x.UnwindTradeAmount,
UnwindNotional = (x.UnwindTradeAmount ?? 0) * countRatio,
UnwindPercentRate = x.UnwindPercentRate ?? 0,
UnwindStockEqvNotional = x.UnwindStockEqvNotional,
CallPut = x.OptionType,
ExceciseType = "现金",
FinalPrice = req.trade_cash.FinalPrice,
UnwindType = req.trade_cash.UnwindType,
ParentTradeCashId = parentTradeCashId,
TradeStatus = tradeStatus
};
if (valuedateBLL.SystemDate.CloseReCheck == 1 || (valuedateBLL.SystemDate.CloseReApprove == 1 && hasProcess))
{
if (req.trade_cash.UnwindType.Contains("到期"))
{
tradeCashReq.IsExpire = true;
tradeCashReq.ValidState = ConsGlobal.InValid;
new TradeExerciseService(this).ApplyExerciseRecheck(tradeCashReq);
}
else
{
new TradeCloseService(this).CloseReCheck(tradeCashReq, false);
}
}
else
{
if (req.trade_cash.UnwindType.Contains("到期"))
{
new TradeCashService(this).ExecutionTradeCash(tradeCashReq);
}
else
{
UnwindTrade(tradeCashReq, trans);
}
}
});
}
public void FinishGroupTradeCash(int TcId)
{
var tradeCash = DbContext.trade_cash.Find(TcId);
if (tradeCash != null)
{
tradeCash.Status = "已执行";
var childrenTradeCash = DbContext.trade_cash.Where(x => x.ParentTradeCashId == TcId).ToList();
tradeCash.Amount = childrenTradeCash.Sum(x => x.Amount);
tradeCash.UnwindPrice = tradeCash.UnwindNotional != 0 ? tradeCash.Amount / tradeCash.UnwindNotional : 0;
var trade = DbContext.trade.Find(tradeCash.TradeId);
tradeCash.UnwindPricePercentRate = TradeHelper.GetPremiumRateByTradeSinglePrice(tradeCash.UnwindPrice, trade.SpotPrice);
var groupActions = DbContext.trade_cash_group_action.Where(x => x.ParentTradeCashId == TcId).ToList();
groupActions.ForEach(x => x.Status = "已完成");
DbContext.SaveChanges();
}
else
{
throw new Exception("未找到该笔了结记录");
}
}
public void CloseReCheck_SetTrade(int tradeId, bool isSwap, bool hasTradeProcess)
{
var td = DbContext.trade.Find(tradeId);
td.OptId = UserId;
td.OptName = UserName;
td.OptDate = OptDate;
if (td.TradeStatus!=ConsTrade.确认成交)
{
throw new Exception("当前交易状态不是确认成交");
}
if (isSwap)
{
td.TradeStatus = ConsTrade.互换待复核;
}
else
{
td.TradeStatus = ConsTrade.平仓待复核;
}
td.CheckStatus = Convert.ToInt32(TradeCheckEnum.StatusOfOld);
//检查是否有交易审批流程(需求②:按交易状态查对应流程,而非只查开仓流程)
var needApproval = (valuedateBLL.SystemDate.CloseReApprove == 1 || isSwap) && TradeProcessCountByCategory(td) > 0;
if (needApproval)
{
// 需求①:进入审批前先判断触发条件——若所有节点都不满足触发条件,跳过审批。
needApproval = NeedApprovalByTrigger(td);
}
if (needApproval)
{
// 需要审批:进入审批流程等待人工审批
InitTradeProcessOrder(td, UserId);
AddTradeOperationHistoryAndSetParentTradeInfo(false, td, isSwap ? "互换审核提交" : "平仓审核提交");
}
else
{
// 不需要审批:只标记 ProcessOrderId=审批通过。
// 互换的 swap_event 记录要等调用方 ApplySwapTrade 的 SaveSwapDeal 执行后才创建,
// 所以互换不在这里调 UpdateTradeProcessLog(否则 FindSwapEvent 找不到记录),
// 由 ApplySwapTrade 在 SaveSwapDeal 之后判断并触发审批通过流程。
td.ProcessOrderId = ProcessTradeLog.审批通过;
}
}
}
///
/// 交易平仓操作结果
///
public class TradeUnwindResultModel
{
public trade Trade;
public trade_cash TradeCash;
///
/// 是否复核审批
///
public bool ApprovalProcess;
//----------------------------
//以下是平仓处理结果
///
/// 是否有配对交易
///
public bool HasPairTrade;
///
/// 是否配对交易平仓成功
///
public bool PairTradeUnwindSuccess;
///
/// 配对交易平仓出错消息
///
public Exception PairTradeUnwindException;
public TradeUnwindResultModel(trade trade)
{
Trade = trade;
}
}
}