291 lines
12 KiB
C#
291 lines
12 KiB
C#
using System.Text;
|
|
using YLErp.BLL;
|
|
using YLErp.Modules.DataProviderModule;
|
|
using YLErp.Modules.MarginModule;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.Modules.TradeModule.DealModule
|
|
{
|
|
public class TradeDelaySettlementService : TradeServiceBase
|
|
{
|
|
public TradeDelaySettlementService(YLBaseService baseService) : base(baseService)
|
|
{
|
|
}
|
|
|
|
public TradeDelaySettlementService(OptUserInfo userInfo) : base(userInfo)
|
|
{
|
|
}
|
|
|
|
private const string key = "ExerciseTradeUnderly";
|
|
|
|
public ExerciseTradeUnderly GetCacheExerciseTradeUnderly()
|
|
{
|
|
|
|
var _reture = DataCacheProvider.GetCache("ExerciseTradeUnderly");
|
|
ExerciseTradeUnderly exerciseTradeUnderly = (ExerciseTradeUnderly)_reture;
|
|
if (_reture == null)
|
|
{
|
|
exerciseTradeUnderly = CheckExerciseTradeUnderly();
|
|
}
|
|
return exerciseTradeUnderly;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 检察当日到期交易的标的状态
|
|
/// </summary>
|
|
/// <param name="valueDate"></param>
|
|
public ExerciseTradeUnderly CheckExerciseTradeUnderly()
|
|
{
|
|
ExerciseTradeUnderly exerciseTradeUnderly = new ExerciseTradeUnderly();
|
|
List<DelaySettlement> delays = GetDelaySettlements();
|
|
exerciseTradeUnderly.underlystr = "";
|
|
exerciseTradeUnderly.datetime = DateTime.Now.ToString("yyyy/MM/dd/ HH:mm:ss");
|
|
if (delays.Any())
|
|
{
|
|
StringBuilder underlyStr = new StringBuilder();
|
|
foreach (var item in delays)
|
|
{
|
|
underlyStr.Append(item.UnderlyCode).Append("(").Append(item.UnderlyState).Append(")").Append(",");
|
|
}
|
|
exerciseTradeUnderly.underlystr = underlyStr.ToString().Substring(0, underlyStr.Length - 1);
|
|
|
|
}
|
|
DataCacheProvider.SetCache(key, exerciseTradeUnderly, DateTime.Today.AddDays(1));
|
|
return exerciseTradeUnderly;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取异常标的列表
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public List<DelaySettlement> GetDelaySettlements(DateTime? date = null)
|
|
{
|
|
var valueDate = date ?? valuedateBLL.ValueDate;
|
|
var lastDate = QdpCalendarHelper.GetNonHolidayDefore(valueDate.AddDays(-1));
|
|
List<DelaySettlement> delays = new List<DelaySettlement>();
|
|
|
|
//结构化交易主交易除外(没有主交易概念),组合交易主交易子交易都得考虑延期处理
|
|
var query = DbContext.trade.Where(x => (x.TradeType != "结构化交易" || x.IsGroup == 1) && x.ValidState != ConsGlobal.InValid && (x.ExerciseDate >= valueDate || x.SettlementFlag == 1) && ConsTrade.PositionTradeStatusList.Contains(x.TradeStatus));
|
|
|
|
var arrUnderlyingCode = query.Select(n => n.UnderlyingCode).Distinct().ToArray();
|
|
|
|
MarginParamProvider marginParam = new MarginParamProvider(OptUser, valueDate);
|
|
marginParam.Initialize(arrUnderlyingCode.ToHashSet(), MarginParamTypeEnum.UpDownLimit);
|
|
|
|
if (arrUnderlyingCode.Any())
|
|
{
|
|
var eodPriceProvider = new EodPriceProvider(valueDate);
|
|
var eodPriceProvidlast = new EodPriceProvider(lastDate);
|
|
|
|
foreach (var item in arrUnderlyingCode)
|
|
{
|
|
if (eodPriceProvider.TryGetEodPrice(item, out var eodPrice))
|
|
{
|
|
DelaySettlement delay = new DelaySettlement();
|
|
if (eodPrice.UnderlyingStatus == "停牌")
|
|
{
|
|
delay.UnderlyState = "停牌";
|
|
}
|
|
else if (eodPriceProvidlast.TryGetPrice(item, SettlementTypeEnum.SettlePrice, out double price))
|
|
{
|
|
if (marginParam.TryGetUpdownLimit(item, out var limit, out var isFixed))
|
|
{
|
|
if (!isFixed)
|
|
{
|
|
limit *= price;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
limit = price * 0.05;
|
|
}
|
|
//注意:price价格可能为负值
|
|
limit = Math.Abs(limit);
|
|
|
|
//涨跌停暂时不使用精确等于处理
|
|
if (price + limit <= eodPrice.ClosePrice)
|
|
{
|
|
delay.UnderlyState = "涨停";
|
|
}
|
|
else if (price - limit >= eodPrice.ClosePrice)
|
|
{
|
|
delay.UnderlyState = "跌停";
|
|
}
|
|
}
|
|
else if (eodPrice.HighPrice == eodPrice.LowPrice && eodPrice.HighPrice != null)
|
|
{
|
|
delay.UnderlyState = "涨跌停";
|
|
}
|
|
if (!string.IsNullOrWhiteSpace(delay.UnderlyState))
|
|
{
|
|
delay.UnderlyCode = item;
|
|
delays.Add(delay);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return delays;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取需要延期交易的交易编号
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public string GetDelayTradeNumber(List<int> updownUnderly)
|
|
{
|
|
var date = valuedateBLL.ValueDate;
|
|
var lastDate = QdpCalendarHelper.GetNonHolidayDefore(date.AddDays(-1));
|
|
var predicate = PredicateBuilder.Create<trade>(t => t.ExerciseDate >= lastDate
|
|
&& t.ExerciseDate <= date
|
|
&& t.TradeStatus == ConsTrade.确认成交
|
|
&& t.ClientId > 0
|
|
&& updownUnderly.Contains(t.UnderlyingId) && t.SettlementFlag == 0 //检查费停牌状态下所有 持仓交易的是否已执行到期
|
|
&& t.ValidState != ConsGlobal.InValid);
|
|
|
|
var tradeNumber = DbContext.trade.Where(predicate).Select(x => x.TradeNumber).ToHashSet();
|
|
return "<br />需要延期结算的交易:<br />" + string.Join(",<br/>", tradeNumber);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取需要延期交易的异常标的id
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public IEnumerable<int> GetDelayUnderlyIds(DateTime? date = null)
|
|
{
|
|
var valueDate = date ?? valuedateBLL.ValueDate;
|
|
var lastDate = QdpCalendarHelper.GetNonHolidayDefore(valueDate.AddDays(-1));
|
|
|
|
//结构化交易主交易除外(没有主交易概念),组合交易主交易子交易都得考虑延期处理
|
|
var query = DbContext.trade.Where(x => (x.TradeType != "结构化交易" || x.IsGroup == 1) && x.ValidState != ConsGlobal.InValid && x.ExerciseDate == valueDate && ConsTrade.PositionTradeStatusList.Contains(x.TradeStatus) && x.TradeType == "收益互换" && x.SettlementFlag != 1);
|
|
|
|
var arrUnderlyingCode = query.Select(n => n.UnderlyingCode).Distinct().ToArray();
|
|
|
|
MarginParamProvider marginParam = new MarginParamProvider(OptUser, valueDate);
|
|
marginParam.Initialize(arrUnderlyingCode.ToHashSet(), MarginParamTypeEnum.UpDownLimit);
|
|
|
|
List<int> ret = new List<int>();
|
|
|
|
if (arrUnderlyingCode.Any())
|
|
{
|
|
var eodPriceProvider = new EodPriceProvider(valueDate);
|
|
var eodPriceProvidlast = new EodPriceProvider(lastDate);
|
|
|
|
foreach (var item in arrUnderlyingCode)
|
|
{
|
|
if (eodPriceProvider.TryGetEodPrice(item, out var eodPrice))
|
|
{
|
|
if (eodPrice.UnderlyingStatus == "停牌")
|
|
{
|
|
ret.Add(eodPrice.UnderlyingId);
|
|
}
|
|
else if (eodPriceProvidlast.TryGetPrice(item, SettlementTypeEnum.SettlePrice, out double price))
|
|
{
|
|
if (marginParam.TryGetUpdownLimit(item, out var limit, out var isFixed))
|
|
{
|
|
if (!isFixed)
|
|
{
|
|
limit *= price;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
limit = price * 0.05;
|
|
}
|
|
//注意:price价格可能为负值
|
|
limit = Math.Abs(limit);
|
|
|
|
//涨跌停暂时不使用精确等于处理
|
|
if (price + limit <= eodPrice.ClosePrice || price - limit >= eodPrice.ClosePrice)
|
|
{
|
|
ret.Add(eodPrice.UnderlyingId);
|
|
}
|
|
}
|
|
else if (eodPrice.HighPrice == eodPrice.LowPrice && eodPrice.HighPrice != null)
|
|
{
|
|
ret.Add(eodPrice.UnderlyingId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
public void ExecuteDelaySettlements(string tradeids, int settlementvalue, out string msg)
|
|
{
|
|
msg = "";
|
|
List<int> ids = new List<int>();
|
|
var _ids = tradeids.Split(',').ToList();
|
|
foreach (var item in _ids)
|
|
{
|
|
ids.Add(Convert.ToInt32(item));
|
|
}
|
|
var Alltrades = DbContext.trade.Where(x => ids.Contains(x.id));
|
|
if (Alltrades.Any(x => x.TradeStatus != ConsTrade.确认成交))
|
|
{
|
|
throw new ServiceException("交易:" + string.Join(".", Alltrades.Where(x => x.TradeStatus != ConsTrade.确认成交).Select(x => x.TradeNumber).ToList()) + ",当前交易状态不符合延期结算要求,无法进行延期结算");
|
|
}
|
|
var notChange = Alltrades.Where(x => x.SettlementFlag == settlementvalue).Count();
|
|
|
|
if (Alltrades.Any(x => x.SettlementFlag != settlementvalue))
|
|
{
|
|
var optType = settlementvalue == 1 ? "手动延期结算" : "延期结算放弃";
|
|
var trades = Alltrades.Where(x => x.SettlementFlag != settlementvalue).ToList();
|
|
using (var trans = BeginTransaction())
|
|
{
|
|
foreach (var item in trades)
|
|
{
|
|
UpdateDelayStatus(item, optType, settlementvalue);
|
|
}
|
|
DbContext.SaveChanges();
|
|
trans.Commit();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new ServiceException("不存在需要修改延期结算状态的交易");
|
|
}
|
|
if (notChange > 0)
|
|
{
|
|
msg = "成功修改" + (Alltrades.Count() - notChange) + "条,不需要修改延期结算状态" + notChange + "条";
|
|
}
|
|
else
|
|
{
|
|
msg = "修改延期结算状态成功";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 修改交易延期状态
|
|
/// </summary>
|
|
/// <param name="trade"></param>
|
|
public void UpdateDelayStatus(trade td, string optType, int SettlementFlag = 1)
|
|
{
|
|
td.SettlementFlag = SettlementFlag;
|
|
td.SettlementFlagDate = DateTime.Now;
|
|
td.SettlementFlagOptId = UserId;
|
|
td.OptId = UserId;
|
|
td.OptName = UserName;
|
|
td.OptDate = DateTime.Now;
|
|
AddTradeOperationHistoryAndSetParentTradeInfo(true, td, optType);
|
|
}
|
|
|
|
}
|
|
|
|
public class ExerciseTradeUnderly
|
|
{
|
|
public string datetime { get; set; }
|
|
|
|
public string underlystr { get; set; }
|
|
}
|
|
|
|
public class DelaySettlement
|
|
{
|
|
public string UnderlyCode { get; set; }
|
|
|
|
public string UnderlyState { get; set; }
|
|
}
|
|
|
|
}
|
|
|
|
|