Files
zszq-trs/YLErpDAL/BLL/MarginCalculation/DongWu/UpDownLimitMargin1Provider.cs
T
2024-05-09 14:06:26 +08:00

259 lines
11 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YLErp.Abstract.DataProviders;
using YLErp.Models;
using YLErp.Modules.DataProviderModule;
using YLErp.Modules.MarginModule;
namespace YLErp.BLL.MarginCalculation.DongWu
{
public class UpDownLimitMargin1Provider : IUpDownLimitProvider
{
private DateTime settleDate;
private string underlyingCode;
readonly IUnderlyingDataProvider underlyingDataProvider;
readonly MarginParamProviderManager marginParamProviderManager;
public UpDownLimitMargin1Provider(DateTime settleDate, string underlyingCode,
MarginParamProviderManager marginParamProviderManager)
{
this.settleDate = settleDate;
this.underlyingCode = underlyingCode;
this.marginParamProviderManager = marginParamProviderManager;
this.underlyingDataProvider = new UnderlyingDataProvider();
}
/// <summary>
/// 计算Margin1涨跌幅
/// 1、当天涨停板的定义:每天可以从交易所获得今天的涨跌停版,举例:设当天的涨跌停是10%,那么day1幅度=-12%到12%
/// 2、封板的定义,获取涨停价、跌停价当天涨跌停版范围使用结算价算出来的,封板:收盘价-当日涨停价价/跌停价的绝对值小于等于2个tick
/// ----------------------------------------
/// T日 T-1日 T-2日 所属情景 Limit(day1幅度)
/// 封板 封板 - 连续封板的第二天 当天涨跌停板+0.02
/// 封板 未封板 - 首日封板 当天涨跌停板+0.03
/// 未封板 封板 封板 封板两天后恢复 当天涨跌停板-0.05
/// 未封板 封板 未封板 昨日封板后恢复 当天涨跌停板-0.03
/// 未封板 未封板 封板/未封板 正常 当天涨停板
/// </summary>
/// <returns></returns>
public virtual InnerUpDownLimit GetUpDownLimit()
{
var t0innerUnderlying = GetInnerUnlyingCode(settleDate);
var t1innerUnderlying = GetInnerUnlyingCode(settleDate.AddDays(-1));
var t2innerUnderlying = GetInnerUnlyingCode(settleDate.AddDays(-2));
var marginRate= new MarginRateManager().GetMarginRate(t0innerUnderlying?.IsCover, t1innerUnderlying?.IsCover, t2innerUnderlying?.IsCover);
var limitRate = t0innerUnderlying.OriginUpDownLimitRate + marginRate;
var innerUnderlying = new InnerUpDownLimit()
{
UnderlyingCode= t0innerUnderlying.UnderlyingCode,
//ClosePrice = t0innerUnderlying.ClosePrice,
IsCover= t0innerUnderlying.IsCover,
IsTouch = t0innerUnderlying.IsTouch,
OriginUpDownLimitRate = t0innerUnderlying.OriginUpDownLimitRate,
UplimitRate = limitRate,
DownLimitRate = -limitRate
};
return innerUnderlying;
}
/// <summary>
/// 查询标的信息(涨跌幅、是否封板,收盘价)
/// -------------------------------------------------------------------
///
/// </summary>
/// <param name="date"></param>
/// <param name="underlyingCode"></param>
/// <returns></returns>
protected InnerUpDownLimit GetInnerUnlyingCode(DateTime date)
{
var um = underlyingDataProvider.GetUnderlying(underlyingCode);
// 查询t0结算价
var t0EodPrice = GetEodPrice(date, underlyingCode);
//var t0SettlePrice = closePrice ?? (t0EodPrice == null ? 0.00 : t0EodPrice.SettlePrice);
var t0HighPrice= t0EodPrice == null ? 0.00 : t0EodPrice.HighPrice??0;
var t0LowPrice = t0EodPrice == null ? 0.00 : t0EodPrice.LowPrice??0;
var t0ClosePrice = t0EodPrice == null ? 0.00 : t0EodPrice.ClosePrice;
// 查询t-1结算价
var t1EodPrice = GetEodPrice(date.AddDays(-1), underlyingCode);
var t1SettlePrice = t1EodPrice == null ? 0.00d : t1EodPrice.SettlePrice;
// 查询t0的涨跌停幅度(t-1结算价*t0涨跌停率)
var limitPrice = GetLimit(date, underlyingCode, t1SettlePrice, out double limitRate);
// t0的涨停价=t-1结算价+t0涨跌停幅度
double upLimitPrice = t1SettlePrice + limitPrice;
double downLimitPrice = t1SettlePrice - limitPrice;
// 是否封板:
// 1.找不到t-1结算价或找不到t0收盘价,则认为未封板
// 2.t0结算价-(t0涨停价/t0跌停价)的绝对值小于等于2个tick,则为封板
var isCover = t0EodPrice == null || t1EodPrice == null ? false : IsCover(t0ClosePrice, upLimitPrice, downLimitPrice, um.PriceTick);
var isTouch = t0EodPrice == null || t1EodPrice == null ? false : IsTouch(t0HighPrice, t0LowPrice, upLimitPrice, downLimitPrice);
var innerUnderlying = new InnerUpDownLimit()
{
UnderlyingCode = underlyingCode,
IsCover = isCover,
IsTouch= isTouch,
OriginUpDownLimitRate = limitRate
};
return innerUnderlying;
}
/// <summary>
/// 获取日终价
/// </summary>
/// <param name="date"></param>
/// <param name="underlyingCode"></param>
/// <returns></returns>
private EodPrice GetEodPrice(DateTime date, string underlyingCode)
{
return EodPriceQueryService.GetEodPrice(date, underlyingCode);
}
/// <summary>
/// 查询涨跌榜
/// </summary>
/// <param name="date"></param>
/// <param name="underlyingCode"></param>
/// <param name="preClosePrice"></param>
/// <param name="limitRate"></param>
/// <returns></returns>
private double GetLimit(DateTime date, string underlyingCode, double preClosePrice, out double limitRate)
{
var mpProvider = marginParamProviderManager.GetMpProvider(date);
double limitPrice = 0d;
if (mpProvider.TryGetUpdownLimit(underlyingCode, out limitRate, out var isFixed))
{
if (!isFixed)
{
limitPrice = limitRate * preClosePrice;
}
}
return limitPrice;
}
/// <summary>
/// 是否封板:收盘价-当日涨停价价/跌停价的绝对值小于等于2个tick
/// </summary>
/// <param name="closePrice"></param>
/// <param name="upLimitPrice"></param>
/// <param name="downLimitPrice"></param>
/// <param name="limit"></param>
/// <param name="tick"></param>
/// <returns></returns>
private bool IsCover(double closePrice, double upLimitPrice, double downLimitPrice, double tick)
{
bool isCover= Math.Abs(closePrice - upLimitPrice) <= 2 * tick || Math.Abs(closePrice - downLimitPrice) <= 2 * tick;
if (!isCover)
{
return closePrice >= upLimitPrice || closePrice <= downLimitPrice;
}
return isCover;
}
/// <summary>
/// 是否触板:最高价>=涨停价或者最低价<=跌停价
/// </summary>
/// <param name="highPrice">最高价</param>
/// <param name="lowerPrice">最低价</param>
/// <param name="upLimitPrice">涨停价</param>
/// <param name="downLimitPrice">跌停价</param>
/// <returns></returns>
private bool IsTouch(double highPrice,double lowerPrice, double upLimitPrice, double downLimitPrice)
{
return highPrice>= upLimitPrice || lowerPrice <= downLimitPrice;
}
/// <summary>
/// 东吴涨跌涨跌幅度管理
/// </summary>
internal class MarginRateManager
{
#region
private const string YesYesYes = "111";
private const string YesYesNo = "110";
private const string YesNONo = "100";
private const string YesNOYes = "101";
private const string NoYesYes = "011";
private const string NoYesNo = "010";
private const string NoNoNo = "000";
private const string NoNoYes = "001";
#endregion
private static readonly Dictionary<string, double> MarginRates = new Dictionary<string, double>()
{
{ YesYesYes, 0.02d },
{ YesYesNo, 0.02d },
{ YesNONo, 0.03d },
{ YesNOYes, 0.03d },
{ NoYesYes, -0.05d },
{ NoYesNo, -0.03d },
{ NoNoNo, 0d },
{ NoNoYes, 0d }
};
private int ConvertToEnum(bool isCover)
{
return isCover ? 1 : 0;
}
public enum CoverEnum
{
Yes = 0,
No = 1,
}
public double GetMarginRate(bool? t0IsCover, bool? t1IsCover, bool? t2IsCover)
{
string key = $"{ConvertToEnum(t0IsCover??false)}{ConvertToEnum(t1IsCover??false)}{ConvertToEnum(t2IsCover??false)}";
return MarginRates[key];
}
}
}
/// <summary>
/// 预付金参数提供管理类
/// </summary>
public class MarginParamProviderManager
{
private HashSet<string> umCodeSet;
private Dictionary<DateTime, MarginParamProvider> marginParamProviders=new Dictionary<DateTime, MarginParamProvider>();
public MarginParamProviderManager(HashSet<string> umCodeSet)
{
this.umCodeSet = umCodeSet;
}
public void Initial(RunMarginCalculationReq req)
{
var t0MpProvider = new MarginParamProvider(req.UserInfo, req.settleDate);
t0MpProvider.Initialize(umCodeSet, MarginParamTypeEnum.UpDownLimit);
marginParamProviders.Add(req.settleDate, t0MpProvider);
var t1MpProvider = new MarginParamProvider(req.UserInfo, req.settleDate.AddDays(-1));
t1MpProvider.Initialize(umCodeSet, MarginParamTypeEnum.UpDownLimit);
marginParamProviders.Add(req.settleDate.AddDays(-1), t1MpProvider);
var t2MpProvider = new MarginParamProvider(req.UserInfo, req.settleDate.AddDays(-2));
t2MpProvider.Initialize(umCodeSet, MarginParamTypeEnum.UpDownLimit);
marginParamProviders.Add(req.settleDate.AddDays(-2), t2MpProvider);
}
public MarginParamProvider GetMpProvider(DateTime date)
{
if (marginParamProviders.ContainsKey(date))
{
return marginParamProviders[date];
}
return null;
}
}
}