Files
zszq-trs/YLErpDAL/Modules/EodModule/SettlementModule/Base/EodVolProvider.cs
T
2024-05-09 14:06:26 +08:00

305 lines
8.8 KiB
C#

using YLErp.DBModels.Consts;
using YLErp.Modules.VolatilityModule;
using YLErp.QdpModule;
namespace YLErp.Modules.EodModule.SettlementModule
{
/// <summary>
/// 结算波动率接口(暂未考虑多标的处理)
/// </summary>
public interface IEodVolProvider
{
double? GetVol(OtcTradeBase td, double spotPrice);
}
#region----持仓波动率----
/// <summary>
/// TradeVol模式持仓波动率提供
/// </summary>
class EodPositionVolProvider_Trade : TradeVolitalityProvider, IEodVolProvider
{
Dictionary<int, double> _overridVolDic;
public EodPositionVolProvider_Trade(DateTime valueDate) : base(valueDate)
{
}
public double? GetVol(OtcTradeBase td, double spotPrice)
{
if (td is null)
{
throw new ArgumentNullException(nameof(td));
}
if (td.id < 1)
{
return null;
}
if (_overridVolDic == null)
{
using (var db = DbContextFactory.GetYLDbContext())
{
_overridVolDic = db.eod_trade_vol_override.Where(x => x.valuedate == _valueDate)
.Select(n => new { n.tradeid, n.vol }).ToDictionary(n => n.tradeid, m => m.vol);
}
}
if (_overridVolDic.TryGetValue(td.id, out var vol))
{
return vol;
}
if (TryGetVol(td.id, td.ExerciseDate.Value, out vol))
{
return vol;
}
return VolatilityHelper.GetTradeVol(_valueDate, td.TradeDate.Value, td.ExerciseDate.Value,
td.TradeOpenVolatility ?? 0, td.TradeCloseVolatility ?? 0, td.NumOfSmoothingDays ?? 0);
}
}
#endregion
#region----曲面波动率----
/// <summary>
/// 曲面波动率模式持仓波动率提供
/// </summary>
class EodUnderlyingVolProvider : UnderlyingVolitalityProvider
{
protected EodUnderlyingVolProvider(DateTime valueDate, IEnumerable<string> volTypes) : base(valueDate, volTypes)
{
}
protected double? InnerGetVol(OtcTradeBase td, string volType, double spotPrice)
{
if (td is null)
{
throw new ArgumentNullException(nameof(td));
}
var userGroup = string.Empty;
if (ConsUserGroup.HasGroup)
{
userGroup = DataCacheProvider.GetAssetUnitDataSource().GetData(td.AssetId)?.UserGroup;
if (string.IsNullOrEmpty(userGroup))
{
throw new Exception($"[结算交易'{td.TradeNumber}'][取{volType}波动率]未能获取用户组!");
}
}
var unVol = GetVol(volType, userGroup, td.UnderlyingCode);
if (unVol == null)
{
return null;
}
var constVol = VolatilityHelper.GetInterpolatedVol(
volConstructionType: PS.Config.ErpElement.SkewMapVolConstruction ? VolConstructionType.SkewMap : VolConstructionType.Normal,
volSurface: unVol,
valueDate: _valueDate,
underlyingCode: td.UnderlyingCode,
exerciseDate: td.ExerciseDate.Value,
strike: td.Strike ?? 0,
isBuy: td.BuySell == "买入",
isCall: td.CallPut == "Call",
spotPrice: spotPrice,
isMoneynessOption: td.IsMoneynessOption == "是",
isEodCalc: true);
return constVol;
}
}
/// <summary>
/// 单个曲面波动率类型
/// </summary>
class EodUnderlyingSingleVolProvider : EodUnderlyingVolProvider, IEodVolProvider
{
readonly string _volType;
public EodUnderlyingSingleVolProvider(DateTime valueDate, string volType)
: base(valueDate, new[] { volType })
{
_volType = volType ?? throw new ArgumentNullException(nameof(volType));
}
public double? GetVol(OtcTradeBase td, double spotPrice)
{
return InnerGetVol(td, _volType, spotPrice);
}
}
/// <summary>
/// 曲面波动率模式持仓波动率提供
/// </summary>
class EodPositionVolProvider_Underlying : EodUnderlyingVolProvider, IEodVolProvider
{
readonly string _volType;
Dictionary<int, double> _overridVolDic;
public EodPositionVolProvider_Underlying(DateTime valueDate, string volType)
: base(valueDate, new[] { volType })
{
_volType = volType ?? throw new ArgumentNullException(nameof(volType));
}
public double? GetVol(OtcTradeBase td, double spotPrice)
{
if (_overridVolDic == null)
{
using (var db = DbContextFactory.GetYLDbContext())
{
_overridVolDic = db.eod_trade_vol_override.Where(x => x.valuedate == _valueDate)
.Select(n => new { n.tradeid, n.vol }).ToDictionary(n => n.tradeid, m => m.vol);
}
}
if (_overridVolDic.TryGetValue(td.id, out var vol))
{
return vol;
}
return InnerGetVol(td, _volType, spotPrice);
}
}
#endregion
#region----对冲波动率----
/// <summary>
/// 对冲波动率提供
/// </summary>
class EodHedgeVolProvider : TradeHedgeVolProvider, IEodVolProvider
{
public EodHedgeVolProvider(DateTime valueDate) : base(valueDate)
{
}
public double? GetVol(OtcTradeBase td, double spotPrice)
{
if (td is null)
{
throw new ArgumentNullException(nameof(td));
}
if (TryGetVol(td.id, out var vol))
{
return vol;
}
return td.TradeSavedVol ?? 0;
}
}
/// <summary>
/// 开仓波动率提供(开仓波动率只在TradeVol模式下结算)
/// </summary>
class EodOpenVolProvider : TradeHedgeVolProvider, IEodVolProvider
{
public EodOpenVolProvider(DateTime valueDate) : base(valueDate)
{
}
public double? GetVol(OtcTradeBase td, double spotPrice)
{
return td?.TradeOpenVolatility;
}
}
#endregion
#region----扩展波动率----
/// <summary>
/// 扩展波动率(光证)提供
/// </summary>
class EodExtendVolProvider_GZ : VarietyVolProvider, IEodVolProvider
{
public EodExtendVolProvider_GZ(DateTime valueDate) : base(valueDate)
{
}
public double? GetVol(OtcTradeBase td, double spotPrice)
{
if (td is null)
{
throw new ArgumentNullException(nameof(td));
}
if (TryGetVol(td.UnderlyingCode, out var vol))
{
return vol;
}
return null;
}
}
/// <summary>
/// 扩展波动率(BidAskVol)提供
/// </summary>
class EodExtendVolProvider_BidAskVol : EodUnderlyingVolProvider, IEodVolProvider
{
public EodExtendVolProvider_BidAskVol(DateTime valueDate)
: base(valueDate, new[] { "报价Ask", "报价Bid" })
{
}
public double? GetVol(OtcTradeBase td, double spotPrice)
{
if (td is null)
{
throw new ArgumentNullException(nameof(td));
}
return InnerGetVol(td, td.BuySell == "买入" ? "报价Ask" : "报价Bid", spotPrice);
}
}
#endregion
/// <summary>
/// 波动率提供者工厂
/// </summary>
public class EodVolProviderFactory
{
public static IEodVolProvider GetEodVolProvider(DateTime valueDate, string volType)
{
switch (volType)
{
case "持仓":
if (PS.Config.IsTradeVol)
{
return new EodPositionVolProvider_Trade(valueDate);
}
volType = BLL.valuedateBLL.SystemDate.EodSettleVolMode.TrimToNull() ?? "财务";
return new EodPositionVolProvider_Underlying(valueDate, volType);
case "开仓":
return new EodOpenVolProvider(valueDate);
case "对冲":
return new EodHedgeVolProvider(valueDate);
case "BidAskVol":
return new EodExtendVolProvider_BidAskVol(valueDate);
case "光证":
return new EodExtendVolProvider_GZ(valueDate);
default:
return new EodUnderlyingSingleVolProvider(valueDate, volType);
}
}
}
}