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

650 lines
22 KiB
C#

using System.Data;
using YLErp.Models;
namespace YLErp.Modules.MarginModule
{
/// <summary>
/// 标的预付金计算参数数据提供服务
/// </summary>
public class MarginParamProvider : YLBaseService
{
readonly DateTime _date;
readonly VarietyMarginParamProvider _vProvider;
readonly Dictionary<string, MarginParamModelEx> _dic;
public MarginParamProvider(OptUserInfo userInfo, DateTime valueDate) : base(userInfo)
{
_date = valueDate;
_vProvider = new VarietyMarginParamProvider(userInfo, valueDate);
_dic = new Dictionary<string, MarginParamModelEx>(StringComparer.OrdinalIgnoreCase);
}
/// <summary>
/// 是否已经初始化
/// </summary>
public bool Initialized => _dic != null && _dic.Count > 0;
#region-----初始化数据----
/// <summary>
/// 初始化数据提供,非必需操作
/// </summary>
public MarginParamProvider Initialize(HashSet<string> underlyingCodes, MarginParamTypeEnum typeEnum)
{
if (underlyingCodes is null || typeEnum == MarginParamTypeEnum.None || !underlyingCodes.Any(n => !string.IsNullOrEmpty(n)))
{
return this;
}
if (_dic.Count > 0)
{
throw new Exception("只允许初始化一次");
}
underlyingCodes.Remove(null);
var udatas = DbContext.underlying_manager.Where(n => underlyingCodes.Contains(n.UnderlyingCode))
.Select(n => new
{
n.UnderlyingCode,
VarietyId = n.CommodityCode == "组合标的" || n.CommodityCode == "篮子标的" ? 0 : n.UnderlyingTypeId
}).ToDictionary(n => n.UnderlyingCode, m => m.VarietyId, StringComparer.OrdinalIgnoreCase);
var removeList = new List<string>();
foreach (var code in underlyingCodes)
{
var mp = new MarginParamModelEx { TypeEnum = typeEnum, VaTypeEnum = typeEnum };
if (udatas.TryGetValue(code, out var vid))
{
mp.VarietyId = vid;
}
else
{
//标的代码在数据库中不存在
removeList.Add(code);
mp.MarginRate = mp.VolatilityRate = mp.UpDownLimit = mp.VarietyId = 0;
}
_dic[code] = mp;
}
underlyingCodes.RemoveWhere(O => removeList.Contains(O));
var enums = new[] { MarginParamTypeEnum.MarginRate, MarginParamTypeEnum.UpDownLimit, MarginParamTypeEnum.VolatilityRate };
foreach (var enm in enums)
{
if ((typeEnum & enm) == enm)
{
InnerInitializeUnderlying(underlyingCodes, enm);
}
}
return this;
}
//用于初始化标的预付金参数数据
private void InnerInitializeUnderlying(IEnumerable<string> underlyingCodes, MarginParamTypeEnum typeEnum)
{
var valueType = GetValueType(typeEnum);
var predicat = PredicateBuilder.Create<UnderlyingHisData>(uh => underlyingCodes.Contains(uh.UnderlyingCode)
&& uh.ValueDate <= _date && uh.ValueType == valueType);
var ugQuery = from uh in DbContext.UnderlyingHisData.Where(predicat)
group uh by uh.UnderlyingCode into g
select new { UnderlyingCode = g.Key, ValueDate = g.Max(n => n.ValueDate) };
var uhQuery = from uh in DbContext.UnderlyingHisData.Where(predicat)
join ug in ugQuery on new { uh.UnderlyingCode, uh.ValueDate } equals new { ug.UnderlyingCode, ug.ValueDate }
select new
{
uh.UnderlyingCode,
uh.Value,
uh.ValueFlag
};
var datas = uhQuery.ToArray();
switch (typeEnum)
{
case MarginParamTypeEnum.MarginRate:
foreach (var data in datas)
{
_dic[data.UnderlyingCode].MarginRate = data.ValueFlag == "N" ? (double?)null : data.Value;
}
break;
case MarginParamTypeEnum.UpDownLimit:
foreach (var data in datas)
{
_dic[data.UnderlyingCode].UpDownLimit = data.ValueFlag == "N" ? (double?)null : data.Value;
_dic[data.UnderlyingCode].IsUpDownLimitFixed = data.ValueFlag != "%";
}
break;
case MarginParamTypeEnum.VolatilityRate:
foreach (var data in datas)
{
_dic[data.UnderlyingCode].VolatilityRate = data.ValueFlag == "N" ? (double?)null : data.Value;
}
break;
}
var unsetMps = _dic.Values.Where(n => !n.GetValue(typeEnum).HasValue).ToArray();
var varietyIds = unsetMps.Select(n => n.VarietyId.Value).ToHashSet();
_vProvider.Initialize(varietyIds, typeEnum);
foreach (var item in unsetMps)
{
item.SetValue(typeEnum, _vProvider.GetData(item.VarietyId.Value, typeEnum));
}
}
#endregion
#region----获取预付金参数----
/// <summary>
/// 获取距valueDate最近的标的预付金率
/// </summary>
public double? GetMarginRate(string underlyingCode)
{
return GetData(underlyingCode, MarginParamTypeEnum.MarginRate);
}
/// <summary>
/// 获取距valueDate最近的标的预付金率
/// </summary>
public bool TryGetMarginRate(string underlyingCode, out double marginRate)
{
return TryGetData(underlyingCode, MarginParamTypeEnum.MarginRate, out marginRate);
}
/// <summary>
/// 获取距valueDate最近的标的涨跌幅度
/// </summary>
public bool TryGetUpdownLimit(string underlyingCode, out double upDownLimit, out bool isFixed)
{
if (TryGetData(underlyingCode, MarginParamTypeEnum.UpDownLimit, out upDownLimit))
{
isFixed = _dic[underlyingCode].IsUpDownLimitFixed;
return true;
}
isFixed = false;
upDownLimit = 0;
return false;
}
/// <summary>
/// 获取距valueDate最近的标的Span波动率变动
/// </summary>
public double? GetVolatilityRate(string underlyingCode)
{
return GetData(underlyingCode, MarginParamTypeEnum.VolatilityRate);
}
/// <summary>
/// 获取距valueDate最近的标的Span波动率变动
/// </summary>
public bool TryGetVolatilityRate(string underlyingCode, out double volatilityRate)
{
return TryGetData(underlyingCode, MarginParamTypeEnum.VolatilityRate, out volatilityRate);
}
//获取特定预付金参数值
private double? GetData(string underlyingCode, MarginParamTypeEnum typeEnum)
{
if (string.IsNullOrEmpty(underlyingCode))
{
return null;
}
//从字典中取数据
if (_dic.TryGetValue(underlyingCode, out var mp) && (typeEnum & mp.TypeEnum) == typeEnum)
{
var dval = mp.GetValue(typeEnum);
if (dval.HasValue || (typeEnum & mp.VaTypeEnum) == typeEnum)
{
return dval;
}
}
else
{
if (mp == null)
{
_dic[underlyingCode] = mp = new MarginParamModelEx();
}
mp.TypeEnum |= typeEnum;
//从underlying_hisdata表中取数据
var valueType = GetValueType(typeEnum);
var uhQuery = from uh in DbContext.UnderlyingHisData
where uh.UnderlyingCode == underlyingCode && uh.ValueDate <= _date && uh.ValueType == valueType
orderby uh.ValueDate descending
select new
{
uh.Value,
uh.ValueFlag
};
var uhData = uhQuery.FirstOrDefault();
if (uhData != null && uhData.ValueFlag != "N")
{
mp.SetValue(typeEnum, uhData.Value);
if (typeEnum == MarginParamTypeEnum.UpDownLimit)
{
mp.IsUpDownLimitFixed = uhData.ValueFlag != "%";
}
return uhData.Value;
}
else if (!DbContext.UnderlyingHisData.Any(uh => uh.UnderlyingCode == underlyingCode && uh.ValueDate > _date && uh.ValueType == valueType && uh.ValueFlag != "N"))
{
var un = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode);
switch (typeEnum)
{
case MarginParamTypeEnum.UpDownLimit:
if (NumberHelper.TryParse(un.UpDownLimit, out var pval, out var isPercent) && pval > 0)
{
mp.SetValue(typeEnum, pval);
mp.IsUpDownLimitFixed = !isPercent;
return pval;
}
break;
case MarginParamTypeEnum.VolatilityRate:
if (NumberHelper.TryParse(un.VolatilityRate, out pval, out isPercent) && pval > 0)
{
mp.SetValue(typeEnum, pval);
return pval;
}
break;
case MarginParamTypeEnum.MarginRate:
if (un.MarginRate.HasValue && un.MarginRate > 0)
{
mp.SetValue(typeEnum, pval = un.MarginRate.Value);
return pval;
}
break;
}
}
}
//从variety_hisdata表中取数据
mp.VaTypeEnum |= typeEnum;
if (!mp.VarietyId.HasValue)
{
var un = DbContext.underlying_manager.Where(n => n.UnderlyingCode == underlyingCode)
.Select(n => new
{
n.CommodityCode,
n.UnderlyingTypeId
}).FirstOrDefault();
mp.VarietyId = un == null || un.CommodityCode == "组合标的" || un.CommodityCode == "篮子标的" ? 0 : un.UnderlyingTypeId;
}
var dvalue = _vProvider.GetData(mp.VarietyId.Value, typeEnum);
mp.SetValue(typeEnum, dvalue);
return dvalue;
}
private bool TryGetData(string underlyingCode, MarginParamTypeEnum typeEnum, out double mpValue)
{
var dvalue = GetData(underlyingCode, typeEnum);
mpValue = dvalue ?? 0;
return dvalue.HasValue;
}
#endregion
public double? GetVarietyData(int varietyId, MarginParamTypeEnum typeEnum)
{
return _vProvider.GetData(varietyId, typeEnum);
}
private static string GetValueType(MarginParamTypeEnum typeEnum)
{
switch (typeEnum)
{
case MarginParamTypeEnum.MarginRate:
return nameof(MarginParamModel.MarginRate);
case MarginParamTypeEnum.UpDownLimit:
return nameof(MarginParamModel.UpDownLimit);
case MarginParamTypeEnum.VolatilityRate:
return nameof(MarginParamModel.VolatilityRate);
default: throw new NotSupportedException();
}
}
}
/// <summary>
/// 品种级别的预付金参数提供
/// </summary>
public class VarietyMarginParamProvider : YLBaseService
{
readonly DateTime _date;
readonly Dictionary<int, MarginParamModelEx> _dic;
bool _hasInitAll;
public VarietyMarginParamProvider(OptUserInfo userInfo, DateTime valueDate) : base(userInfo)
{
_date = valueDate;
_dic = new Dictionary<int, MarginParamModelEx>();
}
#region----初始化----
/// <summary>
/// 初始化数据(非必需)
/// </summary>
public VarietyMarginParamProvider Initialize(MarginParamTypeEnum typeEnum)
{
IEnumerable<int> varietyIds;
if (_hasInitAll)
{
varietyIds = _dic.Keys.ToArray();
}
else
{
_hasInitAll = true;
varietyIds = DbContext.variety.Select(n => n.id).ToArray();
}
return InnerInitializeAllType(varietyIds, typeEnum);
}
/// <summary>
/// 初始化数据(非必需)
/// </summary>
public VarietyMarginParamProvider Initialize(HashSet<int> varietyIds, MarginParamTypeEnum typeEnum)
{
return InnerInitializeAllType(varietyIds, typeEnum);
}
//typeEnum可以是多个并在一起的枚举值
private VarietyMarginParamProvider InnerInitializeAllType(IEnumerable<int> varietyIds, MarginParamTypeEnum typeEnum)
{
var enums = new[] { MarginParamTypeEnum.MarginRate, MarginParamTypeEnum.UpDownLimit, MarginParamTypeEnum.VolatilityRate };
foreach (var enm in enums)
{
if ((typeEnum & enm) == enm)
{
InnerInitializeOneType(varietyIds, enm);
}
}
return this;
}
//typeEnum只能是单个具体的枚举值
private void InnerInitializeOneType(IEnumerable<int> varietyIds, MarginParamTypeEnum typeEnum)
{
if (varietyIds == null || !varietyIds.Any()) return;
foreach (var vid in varietyIds)
{
if (!_dic.TryGetValue(vid, out var mp))
{
_dic.Add(vid, mp = new MarginParamModelEx { VarietyId = vid });
}
mp.TypeEnum |= typeEnum;
}
var valueType = GetValueType(typeEnum);
var baseQuery = DbContext.VarietyHisData.Where(vh => varietyIds.Contains(vh.VarietyId) && vh.ValueDate <= _date && vh.ValueType == valueType);
var vgQuery = from vh in baseQuery
group vh by vh.VarietyId into g
select new { VarietyId = g.Key, ValueDate = g.Max(n => n.ValueDate) };
var vhQuery = from vh in baseQuery
join vg in vgQuery on new { vh.VarietyId, vh.ValueDate } equals new { vg.VarietyId, vg.ValueDate }
select new { vh.VarietyId, vh.Value };
var datas = vhQuery.ToArray();
switch (typeEnum)
{
case MarginParamTypeEnum.MarginRate:
foreach (var data in datas)
{
_dic[data.VarietyId].MarginRate = data.Value;
}
break;
case MarginParamTypeEnum.UpDownLimit:
foreach (var data in datas)
{
_dic[data.VarietyId].UpDownLimit = data.Value;
}
break;
case MarginParamTypeEnum.VolatilityRate:
foreach (var data in datas)
{
_dic[data.VarietyId].VolatilityRate = data.Value;
}
break;
}
}
#endregion
#region----获取预付金参数----
/// <summary>
/// 获取距valueDate最近的品种预付金率
/// </summary>
public double? GetMarginRate(int varietyId)
{
return GetData(varietyId, MarginParamTypeEnum.MarginRate);
}
/// <summary>
/// 获取距valueDate最近的品种预付金率
/// </summary>
public bool TryGetMarginRate(int varietyId, out double marginRate)
{
return TryGetData(varietyId, MarginParamTypeEnum.MarginRate, out marginRate);
}
/// <summary>
/// 获取距valueDate最近的标的涨跌幅度
/// </summary>
public double? GetUpdownLimit(int varietyId)
{
return GetData(varietyId, MarginParamTypeEnum.UpDownLimit);
}
/// <summary>
/// 获取距valueDate最近的标的涨跌幅度
/// </summary>
public bool TryGetUpdownLimit(int varietyId, out double upDownLimit)
{
return TryGetData(varietyId, MarginParamTypeEnum.UpDownLimit, out upDownLimit);
}
/// <summary>
/// 获取距valueDate最近的标的Span波动率变动
/// </summary>
public double? GetVolatilityRate(int varietyId)
{
return GetData(varietyId, MarginParamTypeEnum.VolatilityRate);
}
/// <summary>
/// 获取距valueDate最近的标的Span波动率变动
/// </summary>
public bool GetVolatilityRate(int varietyId, out double volatilityRate)
{
return TryGetData(varietyId, MarginParamTypeEnum.VolatilityRate, out volatilityRate);
}
/// <summary>
///
/// </summary>
public double? GetData(int varietyId, MarginParamTypeEnum typeEnum)
{
if (varietyId < 1) return null;
if (_dic.TryGetValue(varietyId, out var mp) && (mp.TypeEnum & typeEnum) == typeEnum)
{
return mp.GetValue(typeEnum);
}
if (mp == null)
{
_dic[varietyId] = mp = new MarginParamModelEx { VarietyId = varietyId };
}
var valueType = GetValueType(typeEnum);
var hquery = from h in DbContext.VarietyHisData
where h.VarietyId == varietyId && h.ValueDate <= _date && h.ValueType == valueType
orderby h.ValueDate descending
select (double?)h.Value;
var mpValue = hquery.FirstOrDefault();
if (mpValue == null)
{
var va = DataCacheProvider.GetVarietyDataSource().GetData(varietyId);
if (va != null)
{
switch (typeEnum)
{
case MarginParamTypeEnum.MarginRate:
mpValue = va.Margin;
break;
case MarginParamTypeEnum.UpDownLimit:
mpValue = va.UpLimitValue;
break;
case MarginParamTypeEnum.VolatilityRate:
mpValue = va.VolatilityRateValue;
break;
}
}
}
mp.SetValue(typeEnum, mpValue ?? 0);
return mpValue;
}
/// <summary>
///
/// </summary>
public bool TryGetData(int varietyId, MarginParamTypeEnum typeEnum, out double mpValue)
{
var dvalue = GetData(varietyId, typeEnum);
mpValue = dvalue ?? 0;
return dvalue.HasValue;
}
#endregion
private static string GetValueType(MarginParamTypeEnum typeEnum)
{
switch (typeEnum)
{
case MarginParamTypeEnum.MarginRate:
return nameof(MarginParamModel.MarginRate);
case MarginParamTypeEnum.UpDownLimit:
return nameof(MarginParamModel.UpDownLimit);
case MarginParamTypeEnum.VolatilityRate:
return nameof(MarginParamModel.VolatilityRate);
default: throw new NotSupportedException();
}
}
}
/// <summary>
///
/// </summary>
class MarginParamModelEx : MarginParamModel
{
public int? VarietyId;
/// <summary>
/// 用于检查是否已经向数据库请求过
/// </summary>
public MarginParamTypeEnum TypeEnum { get; set; }
/// <summary>
/// 用于检查是否已经从数据库请求过品种关联的数据
/// </summary>
public MarginParamTypeEnum VaTypeEnum { get; set; }
/// <summary>
///
/// </summary>
public double? GetValue(MarginParamTypeEnum typeEnum)
{
switch (typeEnum)
{
case MarginParamTypeEnum.MarginRate:
return MarginRate;
case MarginParamTypeEnum.UpDownLimit:
return UpDownLimit;
case MarginParamTypeEnum.VolatilityRate:
return VolatilityRate;
default: throw new NotSupportedException();
}
}
/// <summary>
///
/// </summary>
public void SetValue(MarginParamTypeEnum typeEnum, double? dvalue)
{
if (dvalue.HasValue)
{
dvalue = Math.Abs(dvalue.Value);
}
switch (typeEnum)
{
case MarginParamTypeEnum.MarginRate:
MarginRate = dvalue;
break;
case MarginParamTypeEnum.UpDownLimit:
UpDownLimit = dvalue;
break;
case MarginParamTypeEnum.VolatilityRate:
VolatilityRate = dvalue;
break;
default: throw new NotSupportedException();
}
}
}
/// <summary>
/// 预付金参数类型枚举
/// </summary>
[Flags]
public enum MarginParamTypeEnum
{
None = 0,
//Span波动率变动
MarginRate = 1 << 0,
//Span涨跌幅度
UpDownLimit = 1 << 1,
//预付金比例
VolatilityRate = 1 << 2,
All = MarginRate | UpDownLimit | VolatilityRate
}
}