- 新增 EodPriceService.SyncUnderlyingIdFromCode:入库前以 UnderlyingCode(FutureContractId) 为准反查真实 UnderlyingId,不一致则告警并自动校正 - SaveEodFuturePrice(web编辑/新增)、SettlementPriceImportService(xlsx上传)、EodSyntheticPriceSaveService(系统合成价) 写入前调用 - 根治'网页端能查到、EOD结算查不到'的失同步问题
243 lines
9.1 KiB
C#
243 lines
9.1 KiB
C#
using System.ComponentModel.DataAnnotations.Schema;
|
|
using YLErp.Modules.DataProviderModule;
|
|
|
|
namespace YLErp.Modules.EodModule.SettlementModule
|
|
{
|
|
/// <summary>
|
|
/// 合成组合标的价格服务
|
|
/// </summary>
|
|
class EodSyntheticPriceSaveService : EodSettleServiceBase
|
|
{
|
|
public const string Step = "合成组合标的价格";
|
|
|
|
public EodSyntheticPriceSaveService(EodSettlementContextBase context) : base(context)
|
|
{
|
|
|
|
}
|
|
|
|
//todo:还没有经过单元测试
|
|
|
|
/// <summary>
|
|
/// 保存组合标的日终结算价格
|
|
/// </summary>
|
|
public void Execute()
|
|
{
|
|
_context?.LogInfo("开始执行,获取组合标的数据");
|
|
|
|
//-------------------------------
|
|
//组合标的获取
|
|
//-------------------------------
|
|
|
|
var query = from a in DbContext.synthetic_underlying
|
|
join b in DbContext.underlying_manager on a.Name equals b.UnderlyingCode
|
|
|
|
join c in DbContext.eod_commodity_future_price.Where(n => n.ValueDate == SettleDate)
|
|
on b.UnderlyingCode equals c.UnderlyingCode into c_t
|
|
from c in c_t.DefaultIfEmpty()
|
|
|
|
join d in DbContext.eod_stock_price.Where(n => n.ValueDate == SettleDate)
|
|
on b.UnderlyingCode equals d.UnderlyingCode into d_t
|
|
from d in d_t.DefaultIfEmpty()
|
|
|
|
where b.CommodityCode == "组合标的" && b.MaturityDate >= SettleDate
|
|
select new synthetic_underlyingDto
|
|
{
|
|
id = a.id,
|
|
Name = a.Name,
|
|
Constant = a.Constant,
|
|
|
|
Coefficient1 = a.Coefficient1,
|
|
Coefficient3 = a.Coefficient3,
|
|
Coefficient2 = a.Coefficient2,
|
|
Coefficient4 = a.Coefficient4,
|
|
|
|
UnderlyingCode1 = a.UnderlyingCode1,
|
|
UnderlyingCode2 = a.UnderlyingCode2,
|
|
UnderlyingCode3 = a.UnderlyingCode3,
|
|
UnderlyingCode4 = a.UnderlyingCode4,
|
|
|
|
RelUnderlyingId = b.id,
|
|
RelUnderlyingInstrumentType = b.UnderlyingInstrumentType,
|
|
|
|
CommodityPrice = c,
|
|
StockPrice = d,
|
|
};
|
|
|
|
var synArr = query.ToArray();
|
|
var synLen = synArr.Length;
|
|
|
|
if (synLen < 1)
|
|
{
|
|
_context?.LogInfo("未获取到组合标的数据");
|
|
return;
|
|
}
|
|
|
|
_context?.LogInfo("获取到的组合标的数量:" + synLen);
|
|
|
|
//-------------------------------
|
|
//更新组合标的价格
|
|
//-------------------------------
|
|
|
|
var eodPriceProvider = _context.GetEodPriceProvider();
|
|
|
|
foreach (var item in synArr)
|
|
{
|
|
GetCombinClosePrice(item, eodPriceProvider);
|
|
}
|
|
|
|
var changes = DbContext.SaveChanges();
|
|
|
|
_context?.LogInfo($"组合标的合成价格后保存到数据库,组合标的数量:{synLen},更新数量:{changes}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取组合标的收盘价
|
|
/// </summary>
|
|
private void GetCombinClosePrice(synthetic_underlyingDto dto, EodPriceProvider eodPriceProvider)
|
|
{
|
|
double closePrice = 0;
|
|
double settlePrice = 0;
|
|
|
|
var arr = new (string, double)[] {
|
|
(dto.UnderlyingCode1,dto.Coefficient1??0),
|
|
(dto.UnderlyingCode2,dto.Coefficient2??0),
|
|
(dto.UnderlyingCode3,dto.Coefficient3??0),
|
|
(dto.UnderlyingCode4,dto.Coefficient4??0)
|
|
};
|
|
|
|
_context?.LogInfo($"[组合标的:{dto.Name}]开始合成收盘价");
|
|
|
|
if (ConsGlobal.InstrumentType.CalcTypeIsFutures(dto.RelUnderlyingInstrumentType))
|
|
{
|
|
foreach ((var underlyingcode, var coefficient) in arr)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(underlyingcode))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (eodPriceProvider.TryGetEodPrice(underlyingcode, out var price))
|
|
{
|
|
closePrice += price.ClosePrice * coefficient;
|
|
settlePrice += price.SettlePrice * coefficient;
|
|
}
|
|
else
|
|
{
|
|
_context?.LogError($"[组合标的:{dto.Name}]未取到标的收盘价,标的代码:{underlyingcode}");
|
|
return;
|
|
}
|
|
}
|
|
|
|
closePrice += dto.Constant ?? 0;
|
|
settlePrice += dto.Constant ?? 0;
|
|
|
|
_context?.LogInfo($"[组合标的:{dto.Name}]收盘价:{closePrice}");
|
|
|
|
if (dto.CommodityPrice != null)
|
|
{
|
|
DbContext.Entry(dto.CommodityPrice).State = EntityState.Unchanged;
|
|
|
|
if (Math.Abs(dto.CommodityPrice.ClosePrice - closePrice) > 0.0001
|
|
|| Math.Abs(dto.CommodityPrice.SettlePrice - settlePrice) > 0.0001)
|
|
{
|
|
dto.CommodityPrice.OptDate = DateTime.Now;
|
|
dto.CommodityPrice.ClosePrice = closePrice;
|
|
dto.CommodityPrice.SettlePrice = settlePrice;
|
|
dto.CommodityPrice.DataSource = EodPriceBase.系统;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dto.CommodityPrice = new eod_commodity_future_price
|
|
{
|
|
UnderlyingCode = dto.Name,
|
|
ValueDate = SettleDate,
|
|
OptDate = DateTime.Now,
|
|
UnderlyingId = dto.RelUnderlyingId,
|
|
ClosePrice = closePrice,
|
|
SettlePrice = settlePrice,
|
|
DataSource = EodPriceBase.系统
|
|
};
|
|
|
|
// 入库前强制 UnderlyingId 与 UnderlyingCode(FutureContractId) 一致,避免网页/结算两套 JOIN 失同步。
|
|
EodPriceService.SyncUnderlyingIdFromCode(DbContext, dto.CommodityPrice);
|
|
|
|
DbContext.eod_commodity_future_price.Add(dto.CommodityPrice);
|
|
}
|
|
|
|
SetDBModelOpt(dto.CommodityPrice);
|
|
}
|
|
else if ("Stock".Equals(dto.RelUnderlyingInstrumentType, StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
foreach ((var underlyingcode, var coefficient) in arr)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(underlyingcode))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (eodPriceProvider.TryGetEodPrice(underlyingcode, out var price))
|
|
{
|
|
closePrice += price.ClosePrice * coefficient;
|
|
}
|
|
else
|
|
{
|
|
_context?.LogError($"[组合标的:{dto.Name}]未取到标的收盘价,标的代码:{underlyingcode}");
|
|
return;
|
|
}
|
|
}
|
|
|
|
closePrice += dto.Constant ?? 0;
|
|
|
|
_context?.LogInfo($"[组合标的:{dto.Name}]收盘价:{closePrice}");
|
|
|
|
if (dto.StockPrice != null)
|
|
{
|
|
DbContext.Entry(dto.StockPrice).State = EntityState.Unchanged;
|
|
|
|
if (Math.Abs(dto.StockPrice.ClosePrice - closePrice) > 0.0001)
|
|
{
|
|
dto.StockPrice.OptDate = DateTime.Now;
|
|
dto.StockPrice.ClosePrice = closePrice;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dto.StockPrice = new eod_stock_price
|
|
{
|
|
UnderlyingCode = dto.Name,
|
|
ValueDate = DateTime.Today,
|
|
OptDate = DateTime.Now,
|
|
ClosePrice = closePrice,
|
|
SettlePrice = closePrice,
|
|
DataSource = EodPriceBase.系统,
|
|
};
|
|
|
|
DbContext.eod_stock_price.Add(dto.StockPrice);
|
|
}
|
|
|
|
SetDBModelOpt(dto.StockPrice);
|
|
}
|
|
else
|
|
{
|
|
_context?.LogInfo($"[组合标的:{dto.Name},未处理]标的类型不支持:" + dto.RelUnderlyingInstrumentType);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// DTO
|
|
/// </summary>
|
|
[NotMapped]
|
|
private class synthetic_underlyingDto : SyntheticUnderlying
|
|
{
|
|
public int RelUnderlyingId { get; set; }
|
|
|
|
public string RelUnderlyingInstrumentType { get; set; }
|
|
|
|
public eod_stock_price StockPrice { get; set; }
|
|
|
|
public eod_commodity_future_price CommodityPrice { get; set; }
|
|
}
|
|
}
|
|
}
|