Files
zszq-trs/Framework/YLErp.Jobs/Imp/GuoYuanPriceSyncJob.cs
T
2024-05-09 14:06:26 +08:00

563 lines
22 KiB
C#

using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations.Schema;
using System.Reflection;
using YLErp.BLL;
using YLErp.DBModels;
using YLErp.Helpers;
using YLErp.Modules;
using YLErp.QdpModule;
using YLErp.Jobs.Configs;
namespace YLErp.Jobs.Imp
{
/// <summary>
/// 国元价格数据同步
/// </summary>
public class GuoYuanPriceSyncJob : BaseJob
{
private readonly YLContext ylDb;
private static readonly Dictionary<string, UpdatetimeModel> runInfo;
private static readonly Dictionary<string, string> irsCurveTypeCodeDict;
private static readonly Dictionary<string, string> cbCurveCodeDict;
private static readonly Dictionary<decimal, string> cbYieldCurveDict;
private static readonly Dictionary<string, string> propertiesDict;
static readonly IYcLogger logger;
private string database = "";
private GuoYuanPriceSyncJobConfig _guoYuanPriceSyncJobConfig;
static GuoYuanPriceSyncJob()
{
logger = LogFactory.GetLogger<GuoYuanPriceSyncJob>();
runInfo = new Dictionary<string, UpdatetimeModel>() {
{ "CGB", new UpdatetimeModel() },
{ "CIB", new UpdatetimeModel() },
{ "FR", new UpdatetimeModel() },
{ "SRS", new UpdatetimeModel() },
{ "SIBO", new UpdatetimeModel() },
{ "FRR", new UpdatetimeModel() }
};
irsCurveTypeCodeDict = new Dictionary<string, string>() {
{ "2", "FR" },
{ "5", "SRS" },
};
cbCurveCodeDict = new Dictionary<string, string>() {
{ "10", "CGB" },
{ "195", "CIB" },
};
cbYieldCurveDict = new Dictionary<decimal, string>() {
{ 0.25m, "3M" },
{ 0.5m, "6M" },
{ 0.75m, "9M" },
{ 1m, "1Y" },
{ 2m, "2Y" },
{ 3m, "3Y" },
{ 5m, "5Y" },
{ 15m, "15Y" },
{ 20m, "20Y" },
{ 10m, "10Y" },
{ 30m, "30Y" },
};
//暂时没用,本来打算反射生成sql语句的;
//Properties =
// typeof(eod_commodity_future_price)
// .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty)
// .Where(O => !O.GetCustomAttributes(typeof(NotMappedAttribute)).Any() && O.Name != nameof(eod_commodity_future_price.id))
// .Select(O =>
// {
// var temp = O.GetCustomAttributes(typeof(ColumnAttribute)).FirstOrDefault() as ColumnAttribute;
// return temp?.Name ?? O.Name;
// }).ToArray();
var eodStockPrice = new eod_stock_price();
propertiesDict =
eodStockPrice.GetType()
.GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.SetProperty)
.Where(O => !O.GetCustomAttributes(typeof(NotMappedAttribute)).Any() && O.Name != nameof(eod_stock_price.id))
.Select(O =>
{
var temp = O.GetCustomAttributes(typeof(ColumnAttribute)).FirstOrDefault() as ColumnAttribute;
var val = O.GetValue(eodStockPrice);
return new
{
Key = temp?.Name ?? O.Name,
Value = val == null ? "null" : $"'{O.GetValue(eodStockPrice)}'"
};
}).ToDictionary(o => o.Key, o => o.Value);
}
public GuoYuanPriceSyncJob(GuoYuanPriceSyncJobConfig guoYuanPriceSyncJobConfig)
{
ylDb = new YLContext();
_guoYuanPriceSyncJobConfig=guoYuanPriceSyncJobConfig;
}
public override Task JobImp()
{
logger.Info("guoyuan-test");
logger.Info("开始执行");
var valueDate = valuedateBLL.ValueDate;
var optTime = DateTime.Now;
InitEodPrice(valueDate, optTime, "");
if (QdpCalendarHelper.IsHoliday(optTime))
{
logger.Info($"{optTime:yyyy-MM-dd} 非交易日,跳过");
return Task.CompletedTask;
}
var tasks = new Task[4];
var connection = _guoYuanPriceSyncJobConfig.ConnStr;//context.MergedJobDataMap["ConnStr"]?.ToString();
database = _guoYuanPriceSyncJobConfig.DataBase;//context.MergedJobDataMap["DataBase"]?.ToString();
logger.Info(connection);
if (optTime.Hour >= 15/* && optTime.Hour < 18*/)
{
foreach (var info in runInfo)
{
if (info.Value.EodData < DateTime.Today)
{
logger.Info("插入日终价格");
InitEodPrice(valueDate, optTime, info.Key);
UpdatePrevClosePrice(info.Key);
info.Value.EodData = DateTime.Today;
}
}
}
try
{
using (var db = new DbHelper(connection))
{
tasks[0] = Task.Run(() =>
SyncCbYieldCurve(db, valueDate, optTime)
);
tasks[1] = Task.Run(() =>
SyncIrsCurve(db, valueDate, optTime)
);
tasks[2] = Task.Run(() =>
SyncShibor(db, valueDate, optTime)
);
tasks[3] = Task.Run(() =>
SyncBaseRate(db, valueDate, optTime)
);
foreach (var t in tasks)
{
t.ContinueWith(O =>
{
if (O.Exception != null)
{
logger.Error(O.Exception);
}
});
}
Task.WaitAll(tasks);
}
}
catch (AggregateException)
{ }
catch (Exception ex)
{
logger.Error(ex);
}
logger.Info("完成");
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
/// <summary>
/// 国债收益率曲线
/// </summary>
/// <param name="db"></param>
/// <param name="valueDate"></param>
/// <param name="optTime"></param>
private void SyncCbYieldCurve(DbHelper db, DateTime valueDate, DateTime optTime)
{
logger.Info("SyncCbYieldCurve开始");
var dbName = "";
if (!string.IsNullOrEmpty(database))
dbName = database + ".";
var curveCodeList = cbCurveCodeDict.Keys.ToArray();
var stepLenghtList = cbYieldCurveDict.Keys.ToArray();
var key = "CGB";
var sqlStr = "SELECT CurveCode,YearsToMaturity,Yield,UpdateTime FROM " + dbName + "Bond_CBYieldCurveAll WHERE CurveCode IN (" + string.Join(",", curveCodeList) + ") AND YearsToMaturity IN (" + string.Join(",", stepLenghtList) + ") AND YieldTypeCode = 1 AND StepTypeCode = 99 AND {0} ORDER BY UpdateTime";
var lastTime = runInfo[key].RealtimeData;
if (lastTime == default)
{
sqlStr = string.Format(sqlStr, $"EndDate = to_date('{optTime.ToString("yyyy-MM-dd")}', 'yyyy-MM-dd HH24:mi:ss')");
}
else
{
sqlStr = string.Format(sqlStr, $"UpdateTime > to_date('{lastTime.ToString("yyyy-MM-dd HH:mm:ss")}', 'yyyy-MM-dd HH24:mi:ss')");
}
logger.Info(sqlStr);
var list = new List<CbYieldCurveModel>();
db.ExecuteSql(sqlStr, dr =>
{
var c = new CbYieldCurveModel
{
CurveCode = dr.GetString(0),
YearsToMaturity = dr.GetInt32(1),
Yield = dr.GetDouble(2),
UpdateTime = dr.GetDateTime(3)
};
list.Add(c);
});
foreach (var item in list)
{
if (!cbCurveCodeDict.ContainsKey(item.CurveCode))
{
continue;
}
if (!cbYieldCurveDict.ContainsKey(item.YearsToMaturity))
{
continue;
}
var code = cbCurveCodeDict[item.CurveCode] + cbYieldCurveDict[item.YearsToMaturity];
logger.Info($"{code},{item.Yield},{item.UpdateTime}");
Flow(key, valueDate, optTime, code, item.Yield, item.UpdateTime);
}
logger.Info($"SyncCbYieldCurve完成");
}
/// <summary>
/// 利率互换收盘曲线
/// </summary>
/// <param name="db"></param>
/// <param name="valueDate"></param>
/// <param name="optTime"></param>
private void SyncIrsCurve(DbHelper db, DateTime valueDate, DateTime optTime)
{
logger.Info("SyncIrsCurve开始");
var dbName = "";
if (!string.IsNullOrEmpty(database))
dbName = database + ".";
var curveTypeCodeList = irsCurveTypeCodeDict.Keys;
var key = "FR";
var sqlStr = "SELECT CueveName,MaturityYield,UpdateTime FROM " + dbName + "Bond_IRSCurveQuote WHERE CurveTypeCode IN (" + string.Join(",", curveTypeCodeList) + ") AND {0} ORDER BY UpdateTime";
var lastTime = runInfo[key].RealtimeData;
if (lastTime == default)
{
sqlStr = string.Format(sqlStr, $"TradingDay = to_date('{optTime.ToString("yyyy-MM-dd")}', 'yyyy-MM-dd HH24:mi:ss')");
}
else
{
sqlStr = string.Format(sqlStr, $"UpdateTime > to_date('{lastTime.ToString("yyyy-MM-dd HH:mm:ss")}', 'yyyy-MM-dd HH24:mi:ss')");
}
logger.Info(sqlStr);
var list = new List<IrsCurveModel>();
db.ExecuteSql(sqlStr, dr =>
{
var c = new IrsCurveModel
{
CueveName = dr.GetString(0),
MaturityYield = dr.GetDouble(1),
UpdateTime = dr.GetDateTime(2)
};
list.Add(c);
});
foreach (var item in list)
{
if (!irsCurveTypeCodeDict.ContainsKey(item.CueveName))
{
continue;
}
var code = irsCurveTypeCodeDict[item.CueveName];//Todo:
logger.Info($"{code},{item.MaturityYield},{item.UpdateTime}");
Flow(key, valueDate, optTime, code, item.MaturityYield, item.UpdateTime);
}
logger.Info($"SyncIrsCurve完成");
}
/// <summary>
/// 上海银行间同业拆借利率
/// </summary>
/// <param name="db"></param>
/// <param name="valueDate"></param>
/// <param name="optTime"></param>
private void SyncShibor(DbHelper db, DateTime valueDate, DateTime optTime)
{
logger.Info("SyncShibor开始");
var dbName = "";
if (!string.IsNullOrEmpty(database))
dbName = database + ".";
var key = "SIBO";
var sqlStr = "SELECT TradingDay,ReportPeriod,OfferedMaturity,WeightAveragePrice,UpdateTime FROM " + dbName + "Bond_SHIBOR WHERE {0} ORDER BY UpdateTime";
var lastTime = runInfo[key].RealtimeData;
if (lastTime == default)
{
sqlStr = string.Format(sqlStr, $"TradingDay = to_date('{optTime.ToString("yyyy-MM-dd")}', 'yyyy-MM-dd HH24:mi:ss')");
}
else
{
sqlStr = string.Format(sqlStr, $"UpdateTime > to_date('{lastTime.ToString("yyyy-MM-dd HH:mm:ss")}', 'yyyy-MM-dd HH24:mi:ss')");
}
logger.Info(sqlStr);
var list = new List<ShiborModel>();
db.ExecuteSql(sqlStr, dr =>
{
var c = new ShiborModel
{
TradingDay = dr.GetDateTime(0),
ReportPeriod = dr.GetInt32(1),
OfferedMaturity = dr.GetString(2),
WeightAveragePrice = dr.GetDouble(3),
UpdateTime = dr.GetDateTime(4)
};
list.Add(c);
});
foreach (var item in list)
{
var code = item.OfferedMaturity + item.ReportPeriod;
logger.Info($"{code},{item.WeightAveragePrice},{item.UpdateTime}");
Flow(key, valueDate, optTime, code, item.WeightAveragePrice, item.UpdateTime);
}
logger.Info($"SyncShibor完成");
}
/// <summary>
/// 回购定盘利率
/// </summary>
/// <param name="db"></param>
/// <param name="valueDate"></param>
/// <param name="optTime"></param>
private void SyncBaseRate(DbHelper db, DateTime valueDate, DateTime optTime)
{
logger.Info("SyncBaseRate开始");
var dbName = "";
if (!string.IsNullOrEmpty(database))
dbName = database + ".";
var key = "FRR";
var sqlStr = "SELECT FR001,FR007,FR014,FDR001,FDR007,FDR014,GC001,GC007,UpdateTime FROM " + dbName + "Bond_BaseRateReference WHERE {0} ORDER BY UpdateTime";
var lastTime = runInfo[key].RealtimeData;
if (lastTime == default)
{
sqlStr = string.Format(sqlStr, $"EndDate = to_date('{optTime.ToString("yyyy-MM-dd")}', 'yyyy-MM-dd HH24:mi:ss')");
}
else
{
sqlStr = string.Format(sqlStr, $"UpdateTime > to_date('{lastTime.ToString("yyyy-MM-dd HH:mm:ss")}', 'yyyy-MM-dd HH24:mi:ss')");
}
logger.Info(sqlStr);
var list = new List<BaseRateModel>();
db.ExecuteSql(sqlStr, dr =>
{
var c = new BaseRateModel
{
FR001 = dr[0] == DBNull.Value ? 0 : dr.GetDouble(0),
FR007 = dr[1] == DBNull.Value ? 0 : dr.GetDouble(1),
FR014 = dr[2] == DBNull.Value ? 0 : dr.GetDouble(2),
FDR001 = dr[3] == DBNull.Value ? 0 : dr.GetDouble(3),
FDR007 = dr[4] == DBNull.Value ? 0 : dr.GetDouble(4),
FDR014 = dr[5] == DBNull.Value ? 0 : dr.GetDouble(5),
GC001 = dr[6] == DBNull.Value ? 0 : dr.GetDouble(6),
GC007 = dr[7] == DBNull.Value ? 0 : dr.GetDouble(7),
UpdateTime = dr[8] == DBNull.Value ? DateTime.MinValue : dr.GetDateTime(8),
};
list.Add(c);
});
foreach (var item in list)
{
Flow(key, valueDate, optTime, nameof(item.FR001), item.FR001, item.UpdateTime);
Flow(key, valueDate, optTime, nameof(item.FR007), item.FR007, item.UpdateTime);
Flow(key, valueDate, optTime, nameof(item.FR014), item.FR014, item.UpdateTime);
Flow(key, valueDate, optTime, nameof(item.FDR001), item.FDR001, item.UpdateTime);
Flow(key, valueDate, optTime, nameof(item.FDR007), item.FDR007, item.UpdateTime);
Flow(key, valueDate, optTime, nameof(item.FDR014), item.FDR014, item.UpdateTime);
Flow(key, valueDate, optTime, nameof(item.GC001), item.GC001, item.UpdateTime);
Flow(key, valueDate, optTime, nameof(item.GC007), item.GC007, item.UpdateTime);
}
logger.Info($"SyncBaseRate完成");
}
#region 镒链系统相关逻辑
private void Flow(string key, DateTime valueDate, DateTime optTime, string code, double price, DateTime updateTime)
{
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(code);
if (um == null)
{
return;
}
um.Price = price;
um.LastUpdateTime = updateTime;
UpdateRealTimePrice(um);
if (runInfo[key].RealtimeData < updateTime)
{
runInfo[key].RealtimeData = updateTime;
}
if (DateTime.Now.Hour > 15 /*&& DateTime.Now.Hour < 18*/)
{
UpdateEodPrice(valueDate, optTime, updateTime, um);
UpdatePrevClosePrice(key);
}
}
/// <summary>
/// 更新前日收盘价
/// </summary>
/// <param name="commodityCode"></param>
/// <returns></returns>
private int UpdatePrevClosePrice(string commodityCode)
{
var sqlStr = $"UPDATE underlying_manager SET PrevClosePrice = Price WHERE CommodityCode = '{commodityCode}';";
return ylDb.Database.ExecuteSqlRaw(sqlStr);
}
/// <summary>
/// 更新日终价格
/// </summary>
/// <param name="valueDate"></param>
/// <param name="optTime"></param>
/// <param name="updateTime"></param>
/// <param name="um"></param>
/// <returns></returns>
private int UpdateEodPrice(DateTime valueDate, DateTime optTime, DateTime updateTime, underlying_manager um)
{
var sqlStr = $"UPDATE eod_stock_price SET ClosePrice = {um.Price},HighPrice = {um.Price},LowPrice = {um.Price},OptDate = '{optTime.ToString("yyyy-MM-dd HH:mm:ss")}',SourceTime = '{updateTime.ToString("yyyy-MM-dd HH:mm:ss")}' WHERE ValueDate = '{updateTime.ToString("yyyy-MM-dd")}' AND StockId = '{um.UnderlyingCode}'";
return ylDb.Database.ExecuteSqlRaw(sqlStr);
}
/// <summary>
/// 更新实时价格
/// </summary>
/// <param name="um"></param>
/// <returns></returns>
private int UpdateRealTimePrice(underlying_manager um)
{
var sqlStr = $"UPDATE underlying_manager SET Price = {um.Price},LastUpdateTime = '{um.LastUpdateTime?.ToString("yyyy-MM-dd HH:mm:ss")}' WHERE UnderlyingCode = '{um.UnderlyingCode}'";
return ylDb.Database.ExecuteSqlRaw(sqlStr);
}
/// <summary>
/// 初始化日终价格
/// <para>存在则更新,不存在则插入</para>
/// </summary>
/// <param name="valueDate">估值日期</param>
/// <param name="optTime">操作时间</param>
/// <returns></returns>
private int InitEodPrice(DateTime valueDate, DateTime optTime, string commodityCode)
{
var count = 0;
var ums = DataCacheProvider.GetUnderlyingDataSource().AsQueryable().Where(O => commodityCode == O.CommodityCode);
foreach (var um in ums)
{
propertiesDict["ValueDate"] = $"'{(um.LastUpdateTime?.Date ?? optTime.Date).ToString("yyyy-MM-dd")}'";
propertiesDict["StockId"] = $"'{um.UnderlyingCode}'";
propertiesDict["ClosePrice"] = $"{um.Price ?? 0}";
propertiesDict["HighPrice"] = $"{um.Price ?? 0}";
propertiesDict["LowPrice"] = $"{um.Price ?? 0}";
propertiesDict["OptDate"] = $"'{optTime.ToString("yyyy-MM-dd HH:mm:ss")}'";
propertiesDict["DataSource"] = $"'系统'";
propertiesDict["ReferencePrice"] = um.Price == null ? "null" : $"{um.Price}";
propertiesDict["UnderlyingStatus"] = $"'正常运行'";
count += ylDb.Database.ExecuteSqlRaw(GetSqlFromPropertiesDict(propertiesDict));
}
return count;
}
private string GetSqlFromPropertiesDict(Dictionary<string, string> dict)
{
var keys = string.Join(",", dict.Keys);
var values = string.Join(",", dict.Values);
var sql = $"REPLACE INTO eod_stock_price({keys}) VALUES ({values})";
return sql;
}
#endregion
#region 内部结构
private class CbYieldCurveModel
{
public string CurveCode { get; set; }
public int YearsToMaturity { get; set; }
public double Yield { get; set; }
public DateTime UpdateTime { get; set; }
}
private class IrsCurveModel
{
public string CueveName { get; set; }
public double MaturityYield { get; set; }
public DateTime UpdateTime { get; set; }
}
private class ShiborModel
{
public DateTime TradingDay { get; set; }
public int ReportPeriod { get; set; }
public string OfferedMaturity { get; set; }
public double WeightAveragePrice { get; set; }
public DateTime UpdateTime { get; set; }
}
private class BaseRateModel
{
public double FR001 { get; set; }
public double FR007 { get; set; }
public double FR014 { get; set; }
public double FDR001 { get; set; }
public double FDR007 { get; set; }
public double FDR014 { get; set; }
public double GC001 { get; set; }
public double GC007 { get; set; }
public DateTime UpdateTime { get; set; }
}
private class UpdatetimeModel
{
/// <summary>
/// 实时价格更新时间
/// </summary>
public DateTime RealtimeData { get; set; }
/// <summary>
/// 日终价格更新时间
/// </summary>
public DateTime EodData { get; set; }
public UpdatetimeModel()
{
RealtimeData = DateTime.MinValue;
EodData = DateTime.MinValue;
}
}
#endregion
}
}