259 lines
11 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|