171 lines
5.9 KiB
C#
171 lines
5.9 KiB
C#
using YLErp.DBModels;
|
|
using YLErp.Modules;
|
|
using YLErp.QdpModule;
|
|
using YLErp.Jobs.Configs;
|
|
|
|
namespace YLErp.Jobs.Imp
|
|
{
|
|
/// <summary>
|
|
/// 国元计算波动率
|
|
/// </summary>
|
|
public class GuoYuanCalcVolJob : BaseJob
|
|
{
|
|
static readonly IYcLogger logger;
|
|
|
|
static GuoYuanCalcVolJob()
|
|
{
|
|
logger = LogFactory.GetLogger<GuoYuanCalcVolJob>();
|
|
}
|
|
|
|
GuoYuanCalcVolJobConfig _guoYuanCalcVolJobConfig;
|
|
public GuoYuanCalcVolJob(GuoYuanCalcVolJobConfig guoYuanCalcVolJobConfig)
|
|
{
|
|
_guoYuanCalcVolJobConfig= guoYuanCalcVolJobConfig;
|
|
}
|
|
|
|
public override Task JobImp()
|
|
{
|
|
var startDate = DateTime.MinValue;
|
|
var endDate = DateTime.MinValue;
|
|
try
|
|
{
|
|
startDate = _guoYuanCalcVolJobConfig.StartDate.Value;
|
|
endDate = _guoYuanCalcVolJobConfig.EndDate.Value;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Error(ex, "参数错误");
|
|
}
|
|
for (DateTime date = startDate; date <= endDate; date = date.AddDays(1))
|
|
{
|
|
try
|
|
{
|
|
logger.Info($"开始计算 {date:yyyy-MM-dd}");
|
|
if (QdpCalendarHelper.IsHoliday(date))
|
|
{
|
|
logger.Info($"{date:yyyy-MM-dd} 非交易日,跳过执行");
|
|
continue;
|
|
}
|
|
Execute(date);
|
|
logger.Info($"计算完成 {date:yyyy-MM-dd}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Error(ex, $"计算异常 {date:yyyy-MM-dd}");
|
|
}
|
|
}
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
#region JobStatus Manager
|
|
static JobStatus jobStatus = JobStatus.Init;
|
|
|
|
public override JobStatus GetJobStatus()
|
|
{
|
|
return jobStatus;
|
|
}
|
|
|
|
public override void SetJobStatus(JobStatus status)
|
|
{
|
|
jobStatus = status;
|
|
}
|
|
#endregion
|
|
|
|
public Task Execute(DateTime valueDate)
|
|
{
|
|
logger.Info($"执行每日计算Vol {valueDate:yyyy-MM-dd}");
|
|
|
|
var db = DbContextFactory.GetYLDbContext();
|
|
var umList =
|
|
(from um in db.underlying_manager
|
|
join vol in db.volatility.Where(O => O.QuotationDate == valueDate)
|
|
on um.UnderlyingCode equals vol.ContractCode into temp
|
|
from vol in temp.DefaultIfEmpty()
|
|
where um.UnderlyingState != "Matured" && um.LaunchState == "1" && vol == null
|
|
select new { um.id, um.UnderlyingCode }).ToArray();
|
|
|
|
var volList = new List<volatility>();
|
|
foreach (var um in umList)
|
|
{
|
|
try
|
|
{
|
|
logger.Info($"{um.UnderlyingCode} 准备计算Vol");
|
|
var prices =
|
|
db.eod_stock_price
|
|
.Where(O =>
|
|
O.UnderlyingCode == um.UnderlyingCode &&
|
|
O.ValueDate < valueDate)
|
|
.Select(O =>
|
|
new
|
|
{
|
|
O.ValueDate,
|
|
O.ClosePrice
|
|
})
|
|
.OrderByDescending(O => O.ValueDate)
|
|
.Take(121).Select(O => O.ClosePrice).ToArray();
|
|
if (prices.Length <= 1)
|
|
{
|
|
logger.Info($"{um.UnderlyingCode} 价格缺失,跳过计算Vol");
|
|
continue;
|
|
}
|
|
if (prices.Length < 121)
|
|
{
|
|
logger.Info($"{um.UnderlyingCode} 价格不足121,继续计算Vol");
|
|
}
|
|
logger.Info($"{um.UnderlyingCode} 计算Vol价格:{prices.ToJson()}");
|
|
var vol = CalcVol(prices);
|
|
logger.Info($"{um.UnderlyingCode} 计算完成 {vol}");
|
|
var midVol = VolatilityBuilder.CreateMoneynessVolBuilder(valueDate, "交易").SetUnderlying(um.id, um.UnderlyingCode).SetOpt(0, "系统计算").Build(vol);
|
|
var bidVol = VolatilityBuilder.CreateMoneynessVolBuilder(valueDate, "报价Bid").SetUnderlying(um.id, um.UnderlyingCode).SetOpt(0, "系统计算").Build(vol);
|
|
var askVol = VolatilityBuilder.CreateMoneynessVolBuilder(valueDate, "报价Ask").SetUnderlying(um.id, um.UnderlyingCode).SetOpt(0, "系统计算").Build(vol);
|
|
volList.Add(midVol);
|
|
volList.Add(bidVol);
|
|
volList.Add(askVol);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
logger.Info($"{um.UnderlyingCode} 计算Vol错误:{ex.ToJson()}");
|
|
}
|
|
}
|
|
db.volatility.AddRange(volList);
|
|
db.SaveChanges();
|
|
|
|
logger.Info("每日计算Vol执行完成");
|
|
return Task.CompletedTask;
|
|
}
|
|
|
|
private double CalcVol(double[] arrData)
|
|
{
|
|
var result = 0d;
|
|
|
|
if (arrData.Length < 2)
|
|
{
|
|
throw new Exception("数据不足!");
|
|
}
|
|
#region Log
|
|
|
|
var log = new double[arrData.Length - 1];
|
|
for (int i = 1; i < arrData.Length; i++)
|
|
{
|
|
log[i - 1] = Math.Log(arrData[i] / arrData[i - 1]);
|
|
}
|
|
|
|
#endregion
|
|
#region STDEV.P
|
|
|
|
var avg = log.Average();
|
|
var sum = log.Sum(O => Math.Pow(O - avg, 2));
|
|
var sqrt = Math.Sqrt(sum / log.Length);
|
|
|
|
#endregion
|
|
#region Annualized
|
|
|
|
result = sqrt * Math.Sqrt(240);
|
|
|
|
#endregion
|
|
|
|
return result;
|
|
}
|
|
}
|
|
}
|