从山证v2.3.0拷贝
This commit is contained in:
@@ -0,0 +1,334 @@
|
||||
using Microsoft.EntityFrameworkCore.Storage;
|
||||
using Qdp.Foundation.Utilities;
|
||||
using YLErp.Commons;
|
||||
using YLErp.CustomizedBizLogic;
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.DBModels.Enums;
|
||||
|
||||
namespace YLErp.Modules.TradeModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 期权交易敲出操作服务
|
||||
/// </summary>
|
||||
public class OptionTradeKnockoutService : YLBaseService
|
||||
{
|
||||
public OptionTradeKnockoutService(YLBaseService baseService) : base(baseService)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存敲出操作资金记录
|
||||
/// </summary>
|
||||
public OptionTradeKnockoutResult Execute(OtcTradeBase td, trade_accumulator_option tdAcc, OptionTradeKnockoutRequest req, IDbContextTransaction trans = null)
|
||||
{
|
||||
var innerTrans = trans == null;
|
||||
|
||||
try
|
||||
{
|
||||
if (innerTrans)
|
||||
{
|
||||
trans = DbContext.Database.BeginTransaction();
|
||||
}
|
||||
|
||||
var result = InnerExecute(td, tdAcc, req);
|
||||
|
||||
//执行事务
|
||||
if (innerTrans)
|
||||
{
|
||||
trans.Commit();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (innerTrans)
|
||||
{
|
||||
trans?.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private OptionTradeKnockoutResult InnerExecute(OtcTradeBase td, trade_accumulator_option tdAcc, OptionTradeKnockoutRequest req)
|
||||
{
|
||||
const string tcAction = ClientCashInCashOut.系统操作_平仓费;
|
||||
|
||||
//trade action
|
||||
var action = CheckAndAddAction(td, req, out var needResettle);
|
||||
|
||||
//client info
|
||||
var client = DbContextFactory.GetClientDbContext(UserInfo).client.Where(n => n.id == td.ClientId)
|
||||
.Select(n => new { n.id, n.Number, n.Name }).FirstOrDefault();
|
||||
if (client == null)
|
||||
{
|
||||
throw new ServiceException($"{td.TradeType}'{td.TradeNumber}'找不到客户信息,客户id:{td.ClientId}");
|
||||
}
|
||||
|
||||
var tradeCashs = DbContext.trade_cash.Where(t => t.TradeId == td.id && t.Action == "系统操作-平仓费" && t.UnwindType == "部分行权" && !t.IsDeleted && t.HappenedDate == req.ValueDate);
|
||||
DbContext.trade_cash.RemoveRange(tradeCashs);
|
||||
|
||||
//trade cash
|
||||
var tc = new trade_cash
|
||||
{
|
||||
TradeId = td.id,
|
||||
|
||||
ValueDate = req.ValueDate,
|
||||
HappenedDate = req.ValueDate,
|
||||
|
||||
Action = tcAction,
|
||||
IsLastAction = true,
|
||||
ExerciseWay = TradeCashExerciseWayEnum.提前终止行权,
|
||||
Amount = req.PaymentAmount,
|
||||
|
||||
ValidState = null,
|
||||
|
||||
ExceciseType = "现金",
|
||||
TradeType = td.BuySell,
|
||||
CallPut = td.CallPut,
|
||||
Notional = td.Notional,
|
||||
TradeAmount = td.TradeAmount,
|
||||
|
||||
UnwindPrice = Math.Abs(td.Notional != 0 ? req.PaymentAmount / td.Notional : 0),
|
||||
UnwindPricePercentRate = Math.Abs(td.Notional != 0 && td.SpotPrice != null && td.SpotPrice != 0 ? req.PaymentAmount / td.Notional / td.SpotPrice.Value : 0),
|
||||
|
||||
OptId = UserId,
|
||||
OptName = UserName,
|
||||
OptDate = DateTime.Now,
|
||||
|
||||
ParentTradeId = 0,
|
||||
ParentTradeCashId = 0,
|
||||
|
||||
Status = TradeCashStatusEnum.已执行,
|
||||
|
||||
FinalPrice = req.UnderlyingPrice,
|
||||
BarrierPrice = tdAcc.KOBarrier,
|
||||
|
||||
UnwindType = null,
|
||||
UnwindNotional = td.Notional,
|
||||
UnwindTradeAmount = td.TradeAmount,
|
||||
UnwindPercentRate = td.Notional / td.OriginalNotional,
|
||||
NotionalPercentRate = td.Notional / td.OriginalNotional,
|
||||
|
||||
AdvanceMoney = 0,
|
||||
IsDeleted = false,
|
||||
SettleDate = req.ValueDate,
|
||||
Comments = null,
|
||||
ConfirmDate = DateTime.MinValue,
|
||||
CurrencyRate = null,
|
||||
ExtraAmount = null,
|
||||
|
||||
Strike = td.Strike,
|
||||
SpotPrice = td.SpotPrice,
|
||||
TradePremium = 0,
|
||||
QuoteAmount = 0,
|
||||
UnwindVol = null,
|
||||
VolType = null,
|
||||
Number = null
|
||||
};
|
||||
|
||||
DbContext.trade_cash.Add(tc);
|
||||
|
||||
DbContext.SaveChanges();
|
||||
|
||||
if (PS.Config.SalesCommissionCalculation == "公式1")
|
||||
{
|
||||
//销售提成
|
||||
new SalesModule.SalesCommissionDetailDataService(UserInfo).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);
|
||||
}
|
||||
//trade_cash_detail
|
||||
var tcd = new trade_cash_detail
|
||||
{
|
||||
TradeId = tc.TradeId,
|
||||
TradeCashId = tc.id,
|
||||
Action = tc.Action,
|
||||
Amount = tc.Amount,
|
||||
ExtraAmount = tc.ExtraAmount,
|
||||
SinglePrice = tc.UnwindPrice,
|
||||
SinglePricePercentRate = tc.UnwindPricePercentRate,
|
||||
ValueDate = tc.ValueDate,
|
||||
OptId = tc.OptId,
|
||||
OptName = tc.OptName,
|
||||
OptDate = DateTime.Now
|
||||
};
|
||||
DbContext.trade_cash_detail.Add(tcd);
|
||||
|
||||
//client cash
|
||||
var cashInOutRecord = new ClientCashInCashOut
|
||||
{
|
||||
Direction = "应收",
|
||||
Number = UniqueTimeId.GetStr(),
|
||||
ClientId = client.id,
|
||||
ClientNumber = client.Number,
|
||||
ClientName = client.Name,
|
||||
Money = -tc.Amount,
|
||||
HappenDate = req.ValueDate,
|
||||
State = ClientCashInCashOut.已确认,
|
||||
OptDate = tc.OptDate,
|
||||
OptId = tc.OptId,
|
||||
OptName = tc.OptName,
|
||||
CreateDate = tc.OptDate,
|
||||
CreatorId = tc.OptId,
|
||||
CreatorName = tc.OptName,
|
||||
TradeId = td.id,
|
||||
TradeCashId = tc.id,
|
||||
Action = tcAction,
|
||||
TradeNumber = td.TradeNumber,
|
||||
IsGroup = td.IsGroup
|
||||
};
|
||||
DbContext.ClientCashInCashOut.Add(cashInOutRecord);
|
||||
|
||||
//end
|
||||
|
||||
action.CashId = tc.id;
|
||||
|
||||
DbContext.SaveChanges();
|
||||
|
||||
return new OptionTradeKnockoutResult
|
||||
{
|
||||
NeedResettle = needResettle,
|
||||
TradeCash = tc,
|
||||
TradeAction = action
|
||||
};
|
||||
}
|
||||
|
||||
//检查已有的action并在数据库上下文中添加敲出action(此时action还没有cashid)
|
||||
private TradeAction CheckAndAddAction(OtcTradeBase td, OptionTradeKnockoutRequest req, out bool needResettle)
|
||||
{
|
||||
var tradeId = td.id;
|
||||
var sysDate = BLL.valuedateBLL.ValueDate;
|
||||
var actions = DbContext.TradeAction.Where(n => n.TradeId == tradeId && n.IsValid).ToArray();
|
||||
|
||||
//存在未审核通过的操作
|
||||
if (actions.Any(n => n.CheckFlag > 0 && n.CheckFlag < byte.MaxValue))
|
||||
{
|
||||
throw new ServiceException($"{td.TradeType}交易'{td.TradeNumber}'存在未审核通过的操作,执行敲出操作失败");
|
||||
}
|
||||
|
||||
//在这里敲出了结已经被检查
|
||||
if (actions.Any(n => n.ActionFlag == TradeActionHelper.Flag_FullClosed))
|
||||
{
|
||||
throw new ServiceException($"{td.TradeType}交易'{td.TradeNumber}'已完全了结,执行敲出操作失败");
|
||||
}
|
||||
|
||||
//存在后续的资金记录(观察日资金或者了结资金)
|
||||
if (!req.IgnoreLaterCashRecords && actions.Any(n => n.ValueDate > req.ValueDate && n.CashId > 0))
|
||||
{
|
||||
throw new ServiceException($"{td.TradeType}交易'{td.TradeNumber}'存在后续的资金记录,执行敲出操作失败");
|
||||
}
|
||||
|
||||
needResettle = false;
|
||||
|
||||
//如果观察日存在转远期的操作行为,这里暂时不进行处理
|
||||
|
||||
//检查观察日是否已经存在资金记录,如果有的话说明曾进行过观察,此时需要进行无效处理
|
||||
var tdObActions = actions.Where(n => n.ValueDate == sysDate && n.CashId > 0).ToArray();
|
||||
if (tdObActions.Any())
|
||||
{
|
||||
var existsTradeCashs = new Lazy<IEnumerable<trade_cash>>(
|
||||
() => DbContext.trade_cash.Where(t => t.TradeId == tradeId && t.ValueDate == req.ValueDate && t.ValidState != ConsGlobal.InValid && !t.IsDeleted));
|
||||
|
||||
var existsTradeCashDetails = new Lazy<IEnumerable<trade_cash_detail>>(
|
||||
() => DbContext.trade_cash_detail.Where(t => t.TradeId == tradeId && t.ValueDate == req.ValueDate));
|
||||
|
||||
var existsClientCashs = new Lazy<IEnumerable<ClientCashInCashOut>>(
|
||||
() => DbContext.ClientCashInCashOut.Where(t => t.ClientId == td.ClientId && t.TradeId == tradeId && t.HappenDate >= req.ValueDate && t.ValidState != ConsGlobal.InValid));
|
||||
|
||||
foreach (var a in tdObActions)
|
||||
{
|
||||
if ((a.ActionType == TradeActionType.ObCoupon || a.ActionType == TradeActionType.ObCash)
|
||||
&& a.ActionFlag == TradeActionHelper.Flag_CashAtHit)
|
||||
{
|
||||
a.IsValid = false;
|
||||
var tc = existsTradeCashs.Value.FirstOrDefault(n => n.id == a.CashId.Value);
|
||||
if (tc != null)
|
||||
{
|
||||
needResettle = true;
|
||||
tc.ValidState = ConsGlobal.InValid;
|
||||
//client cash
|
||||
var cc = existsClientCashs.Value.FirstOrDefault(n => n.TradeCashId == tc.id);
|
||||
if (cc != null)
|
||||
{
|
||||
cc.ValidState = ConsGlobal.InValid;
|
||||
}
|
||||
//trade_cash_detail
|
||||
var details = existsTradeCashDetails.Value.Where(n => n.TradeCashId == tc.id).ToArray();
|
||||
DbContext.trade_cash_detail.RemoveRange(details);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return DbContext.TradeAction.Add(new TradeAction
|
||||
{
|
||||
TradeId = tradeId,
|
||||
ValueDate = req.ValueDate,
|
||||
ActionRemark = "敲出",
|
||||
ActionFlag = TradeActionHelper.Flag_FullClosed,
|
||||
ActionType = TradeActionType.KnockOut,
|
||||
CashId = 0,
|
||||
CreateTime = DateTime.Now,
|
||||
IsValid = true,
|
||||
OptId = UserId,
|
||||
ActionData = null,
|
||||
BackId = null,
|
||||
CheckFlag = 0
|
||||
}).Entity;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 期权交易敲出执行请求
|
||||
/// </summary>
|
||||
public class OptionTradeKnockoutRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 操作日期
|
||||
/// </summary>
|
||||
public DateTime ValueDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标的价格
|
||||
/// </summary>
|
||||
public double UnderlyingPrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 支付金额
|
||||
/// </summary>
|
||||
public double PaymentAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否忽略后续资金记录的检查
|
||||
/// </summary>
|
||||
public bool IgnoreLaterCashRecords { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 期权交易敲出执行结果
|
||||
/// </summary>
|
||||
public class OptionTradeKnockoutResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否需要重新收盘
|
||||
/// </summary>
|
||||
public bool NeedResettle { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public TradeAction TradeAction { get; set; }
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public trade_cash TradeCash { get; set; }
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user