1900 lines
85 KiB
C#
1900 lines
85 KiB
C#
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
|
||
{
|
||
/// <summary>
|
||
/// 交易平仓操作
|
||
/// </summary>
|
||
public class TradeUnwindService : TradeCashService
|
||
{
|
||
public TradeUnwindService(YLBaseService baseService) : base(baseService)
|
||
{
|
||
}
|
||
|
||
public TradeUnwindService(OptUserInfo userInfo) : base(userInfo)
|
||
{
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// isPairTrade是否 配对交易平仓
|
||
/// 规则:配对被执行的那一条的amount(trade_cash表格)和money(clientcashincashout 表格)应该是手动执行那一条的数值*-1
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 来自:UnwindTradeJson
|
||
/// </summary>
|
||
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 && HasTradeProcess())
|
||
{
|
||
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<int> { 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<int> { 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();
|
||
}
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 分组了结 主交易平仓复核
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
/// <returns></returns>
|
||
/// <exception cref="ServiceException"></exception>
|
||
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 && HasTradeProcess())
|
||
{
|
||
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<int> { 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();
|
||
}
|
||
}
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
///
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 互换交易平仓
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
/// <param name="reqFromFrontUser">请求是否来自前端用户</param>
|
||
/// <returns></returns>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 提交互换收益结算申请
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 审批通过互换交易申请
|
||
/// </summary>
|
||
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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 获取互换收益结算执行后需要删除的后续trade cash ids
|
||
/// </summary>
|
||
private IEnumerable<int> 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;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 黑箱交易主交易tradecash保存子交易了结费用加和的值
|
||
/// clientcashincashout保存一条0的记录
|
||
/// 主要为了解决我们是按照子交易进行结算,但是客户结算报告,又想以主交易来展示主交易资金
|
||
/// </summary>
|
||
/// <param name="req"></param>
|
||
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();
|
||
}
|
||
}
|
||
/// <summary>
|
||
/// 修改交易分组了结 标识
|
||
/// </summary>
|
||
/// <param name="tradeId"></param>
|
||
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);
|
||
|
||
//检查是否有交易审批流程
|
||
if ((valuedateBLL.SystemDate.CloseReApprove == 1 || isSwap) && hasTradeProcess)
|
||
{
|
||
//如果有审批组
|
||
InitTradeProcessOrder(td, UserId);
|
||
}
|
||
|
||
AddTradeOperationHistoryAndSetParentTradeInfo(false, td, isSwap ? "互换审核提交" : "平仓审核提交");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 交易平仓操作结果
|
||
/// </summary>
|
||
public class TradeUnwindResultModel
|
||
{
|
||
public trade Trade;
|
||
|
||
public trade_cash TradeCash;
|
||
|
||
/// <summary>
|
||
/// 是否复核审批
|
||
/// </summary>
|
||
public bool ApprovalProcess;
|
||
|
||
//----------------------------
|
||
//以下是平仓处理结果
|
||
|
||
/// <summary>
|
||
/// 是否有配对交易
|
||
/// </summary>
|
||
public bool HasPairTrade;
|
||
|
||
/// <summary>
|
||
/// 是否配对交易平仓成功
|
||
/// </summary>
|
||
public bool PairTradeUnwindSuccess;
|
||
|
||
/// <summary>
|
||
/// 配对交易平仓出错消息
|
||
/// </summary>
|
||
public Exception PairTradeUnwindException;
|
||
|
||
public TradeUnwindResultModel(trade trade)
|
||
{
|
||
Trade = trade;
|
||
}
|
||
}
|
||
}
|