从山证v2.3.0拷贝
This commit is contained in:
@@ -0,0 +1,229 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user