Files
zszq-trs/YLErpDAL/Modules/TradeModule/ExoticOptionModule/DoubleSharkOptionKnockoutService.cs
T
2024-05-09 14:06:26 +08:00

230 lines
10 KiB
C#

using YLErp.Abstract.DataProviders;
using YLErp.BLL;
using YLErp.DBModels.Consts;
using YLErp.Model;
using YLErp.Modules.DataProviderModule;
using YLErp.QdpModule;
namespace YLErp.Modules.TradeModule.ExoticOptionModule
{
/// <summary>
/// 双鲨期权敲出操作
/// 迁移自:trade_double_sharkfin_optionBLL
/// </summary>
public class DoubleSharkOptionKnockoutService : TradeCashServiceEx
{
public DoubleSharkOptionKnockoutService(YLBaseService baseService) : base(baseService)
{
}
public DoubleSharkOptionKnockoutService(OptUserInfo userInfo) : base(userInfo)
{
}
/// <summary>
/// 检出敲入敲出
/// </summary>
public void CheckKnockoutStatus(DateTime valueDate, IEodPriceProviderV2 priceProvider, DateTime? startDate = null
, Action<OtcTrade, trade_double_sharkfin_option> afterKnowInOut = null, System.Collections.Generic.IEnumerable<int> clienIds = null)
{
if (priceProvider is null)
{
priceProvider = new EodPriceProvider(valueDate);
}
if (startDate == null)
{
startDate = valueDate.AddYears(-5);
}
var query = from td in DbContext.trade
join tb in DbContext.trade_double_sharkfin_option on td.id equals tb.TradeId
where td.TradeDate > startDate.Value && td.TradeDate <= valueDate
&& string.IsNullOrEmpty(tb.KnockInOutStatus)
&& td.TradeType == "双鲨期权"
&& ConsTrade.确认成交 == td.TradeStatus
&& td.ValidState != ConsGlobal.InValid
&& td.DividendDate < valueDate
select new
{
trade = td,
tradeDbShark = tb
};
#region 增加客户筛选 tw
if (clienIds != null)
{
query = query.Where(l => clienIds.Contains(l.trade.ClientId));
}
#endregion
var trades = query.ToList();
if (trades == null || !trades.Any())
{
return;
}
//检查是否敲出
var tradeIds = trades.Select(x => x.trade.id).ToList();
var manuallyTradeObservationPrices = DbContext.manually_trade_observation_price
.Where(x => tradeIds.Contains(x.TradeId) && x.ValueDate == valueDate).ToDictionary(n => n.TradeId);
foreach (var tr in trades)
{
if (tr.trade.ExerciseDate < valueDate)
{
continue;//已到期交易不再观察;
}
var tradeStatus = tr.trade.TradeStatus;
var observationDates = QdpHelper.GetObservationDatesFromString(tr.tradeDbShark.ObservationDates);
//每日观察或者当前结算日是观察日的时候,才检查是否会敲敲出
if (observationDates == null || observationDates.Contains(valueDate) || !tr.tradeDbShark.IsDiscrete)
{
//根据是否为离散观察来确定用来比较的价格
//如果是离散观察,只用收盘价比较
//如果是连续观察,使用最高价和最低价
double? upPrice, lowPrice;
if (manuallyTradeObservationPrices.TryGetValue(tr.trade.id, out var manuallyTradeObservationPrice))
{
upPrice = manuallyTradeObservationPrice.Price;
lowPrice = manuallyTradeObservationPrice.Price;
}
else if (!priceProvider.TryGetEodPrice(tr.trade.UnderlyingCode, out var eodprice))
{
throw new Exception($"[{tr.trade.TradeType}:{tr.trade.TradeNumber},标的:{tr.trade.UnderlyingCode}]未找到结算价");
}
else if (tr.tradeDbShark.IsDiscrete)
{
upPrice = eodprice.ClosePrice;
lowPrice = eodprice.ClosePrice;
}
else
{
upPrice = eodprice.HighPrice;
lowPrice = eodprice.LowPrice;
}
var oldKnockInOutStatus = tr.tradeDbShark.KnockInOutStatus;
CheckDoubleSharkFinKnockOutStatus(tr.trade, tr.tradeDbShark, valueDate, upPrice, lowPrice);
if (oldKnockInOutStatus != tr.tradeDbShark.KnockInOutStatus)
{
var KnockInOutStatus = tr.tradeDbShark.KnockInOutStatus == ConsTrade.KnockState.KnockedIn ? "敲入" : "敲出";
AddTradeOperationHistoryAndSetParentTradeInfo(false, tr.trade, KnockInOutStatus, KnockInOutStatus);
}
if (tradeStatus != tr.trade.TradeStatus|| oldKnockInOutStatus != tr.tradeDbShark.KnockInOutStatus)
{
//删除E/Bod_Trade记录
RemoveEodTradeAndFutureInfo(false, tr.trade.id, valueDate);
}
if (afterKnowInOut != null && DbContext.Entry(tr.tradeDbShark).State == EntityState.Modified)
{
afterKnowInOut(tr.trade, tr.tradeDbShark);
}
}
//更新,不能放到循环外,黑箱交易的子交易相互有依赖关系
DbContext.SaveChanges();
}
}
public void CheckDoubleSharkFinKnockOutStatus(OtcTradeBase td, trade_double_sharkfin_option tradeDbShark, DateTime valuedate, double? upPrice, double? lowPrice)
{
var barrierHigh = td.IsMoneynessOptionData ? tradeDbShark.BarrierHigh * td.SpotPrice : tradeDbShark.BarrierHigh;
var barrierLow = td.IsMoneynessOptionData ? tradeDbShark.BarrierLow * td.SpotPrice : tradeDbShark.BarrierLow;
if (upPrice >= barrierHigh || lowPrice <= barrierLow)
{
var useRebate = lowPrice <= barrierLow;
var price = upPrice >= barrierHigh ? upPrice : lowPrice;
tradeDbShark.KnockInOutStatus = ConsTrade.KnockState.KnockedOut;
tradeDbShark.KnockInOutDate = valuedate;
td.TradeStatus = ConsTrade.已平仓;
td.UnWindDate = valuedate;
SaveDoubleSharkFinRebateCash(td, tradeDbShark, price, valuedate, useRebate);
}
}
/// <summary>
/// 双鲨期权敲出,应获得rebate,保存相应的资金信息
/// </summary>
public trade_cash SaveDoubleSharkFinRebateCash(OtcTradeBase td, trade_double_sharkfin_option tradeDbShark, double? closePrice, DateTime valueDate, bool useRebate, bool saveChanges = true)
{
double rebate, rebateRate;
var spotPrice = td.SpotPrice ?? 0;
if (td.IsUsePremiumRate == true)
{
rebateRate = (useRebate ? tradeDbShark.RebateRate : tradeDbShark.RebateHighRate) ?? 0;
rebate = rebateRate * spotPrice;
}
else
{
rebate = (useRebate ? tradeDbShark.Rebate : tradeDbShark.RebateHigh) ?? 0;
rebateRate = spotPrice > 0 ? rebate / spotPrice : 0;
}
var req = new TradeCashReq
{
UnwindNotional = td.Notional,
UnwindPercentRate = td.OriginalNotional > 0 ? td.Notional / td.OriginalNotional.Value : 0,
FinalPrice = closePrice,
UnwindPrice = rebate,
UnwindPricePercentRate = rebateRate,
Notional = td.Notional,
TradeAmount = td.TradeAmount,
ValueDate = valueDate,
HappenedDate = valueDate,
BarrierPrice = useRebate ? tradeDbShark.BarrierLow : tradeDbShark.BarrierHigh
};
req.UnwindFee = req.UnwindNotional * (req.UnwindPrice ?? 0) + ((req.UnwindNotional / td.OriginalNotional * td.OriginalPrincipalSum) ?? 0);
if(valuedateBLL.SystemDate.UnwindAmountAngle == 1)
{
req.UnwindFee = req.UnwindFee * (td.BuySell == "卖出" ? -1 : 1);
}
if (valuedateBLL.SystemDate.UnwindSinglePriceAngle == 1)
{
req.UnwindPrice = req.UnwindPrice * (td.BuySell == "卖出" ? -1 : 1);
}
var tc = CloseTrade_TradeCashSave(td, req, isFromRecheckOrKO: true, isLastAction: true, saveChanges: false);
tc.ValidState = ConsGlobal.Valid;
tc.ExerciseWay = TradeCashExerciseWayEnum.提前终止行权;
if (tradeDbShark.RebateType == "AtEnd")
{
tc.ValueDate = td.ExerciseDate.Value;
tc.HappenedDate = valueDate;
}
//加入平仓份额和平仓日期
td.UnWindDate = tc.ValueDate;
if (td.IsGroup == 2 && td.ParentTradeId > 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;
}
else
{
tc.ParentTradeId = td.ParentTradeId;
tc.ParentTradeCashId = SaveGroupUnwindCash(td, tc.ValueDate, tc.Amount, closePrice ?? 0, out var continueTradeCashHandle).id;
}
}
if (saveChanges)
{
SaveTradeCashDetail(tc);
//增加出入金记录
new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, tc, tc.ValueDate);
}
return tc;
}
}
}