Files
zszq-trs/YLErpDAL/Modules/UnderlyingModule/UnderlyingDalService.cs
T

691 lines
28 KiB
C#

using System.Data;
using YieldChain.Helpers;
using YLErp.BLL;
using YLErp.DBModels.Helpers;
using YLErp.Model;
using YLErp.Models;
namespace YLErp.Modules.UnderlyingModule
{
/// <summary>
/// 标的数据操作服务
/// </summary>
public class UnderlyingDalService : YLBaseService
{
public UnderlyingDalService(OptUserInfo userInfo) : base(userInfo)
{
}
/// <summary>
/// 获取数据详情
/// </summary>
public UnderlyingManagerDto GetDetail(int id)
{
var um = DbContext.underlying_manager.AsNoTracking().FirstOrDefault(n => n.id == id);
if (um == null)
{
return null;
}
var dto = new UnderlyingManagerDto();
ObjectHelper.MapValues(dto, um);
dto.HisDataList = DbContext.UnderlyingHisData.Where(n => n.UnderlyingCode == um.UnderlyingCode)
.OrderBy(n => n.ValueDate)
.Select(n => new HistoryData { Value = n.Value, ValueDate = n.ValueDate, ValueType = n.ValueType, ValueFlag = n.ValueFlag }).ToArray();
return dto;
}
/// <summary>
/// 获取所有有效的商品期货标的
/// </summary>
public IEnumerable<string> GetAllValidCommodityFutureCodes(DateTime minMaturityDate)
{
var datas = DbContext.underlying_manager.Where(n => n.MaturityDate >= minMaturityDate &&
n.UnderlyingInstrumentType == "CommodityFutures" &&
n.UnderlyingCode != null && n.UnderlyingType != "组合标的")
.Select(n => n.UnderlyingCode).ToArray();
Array.Sort(datas);
return datas;
}
/// <summary>
/// 保存组合标的数据
/// </summary>
public int SaveSyntheticUnderlying(SyntheticUnderlyingDto reqModel, out SyntheticUnderlying dbModel)
{
if (reqModel is null)
{
throw new ArgumentNullException(nameof(reqModel));
}
if (string.IsNullOrWhiteSpace(reqModel.Name))
{
throw new ServiceException("合成标的代码 不能为空");
}
if (DbContext.synthetic_underlying.Any(n => n.Name == reqModel.Name && n.id != reqModel.id))
{
throw new ServiceException("合成标的代码 已经存在");
}
var isAddNew = reqModel.id <= 0;
dbModel = null;
if (isAddNew)
{
DbContext.synthetic_underlying.Add(dbModel = new SyntheticUnderlying());
}
else
{
dbModel = DbContext.synthetic_underlying.FirstOrDefault(n => n.Name == reqModel.UnderlyingTipsInfo);
if (dbModel == null)
{
isAddNew = true;
DbContext.synthetic_underlying.Add(dbModel = new SyntheticUnderlying());
reqModel.id = 0;
}
else if (DbContext.trade.Any(trade => trade.UnderlyingCode == reqModel.UnderlyingTipsInfo && trade.ValidState != ConsGlobal.InValid))
{
throw new ServiceException("系统存在使用此组合标的的交易,不能修改");
}
}
if (isAddNew && DbContext.underlying_manager.Any(n => n.UnderlyingCode == reqModel.UnderlyingTipsInfo))
{
throw new ServiceException("当前组合标的的标的代码在系统中已经存在,无法重复新增");
}
//复制值
DbContext.Entry(dbModel).CurrentValues.SetValues(reqModel);
dbModel.Name = dbModel.UnderlyingTipsInfo;
//----------------------------------
// 获取最小的到期日
//----------------------------------
var underlyingCodes = new string[] {
dbModel.UnderlyingCode1.TrimToNull(),
dbModel.UnderlyingCode2.TrimToNull(),
dbModel.UnderlyingCode3.TrimToNull(),
dbModel.UnderlyingCode4.TrimToNull(),
};
underlyingCodes = underlyingCodes.Where(n => !string.IsNullOrEmpty(n)).ToArray();
var underlyings = DbContext.underlying_manager
.Where(u => underlyingCodes.Contains(u.UnderlyingCode))
.Select(u => new
{
u.UnderlyingCode,
u.MaturityDate,
u.TradeUnit,
u.QuoteUnit,
u.UnderlyingInstrumentType,
u.MarketCode,
u.MarketName
}).ToArray();
if (underlyings.Length != underlyingCodes.Length)
{
var missingCode = underlyingCodes.Where(n => !underlyings.Any(m => n.Equals(m.UnderlyingCode, StringComparison.OrdinalIgnoreCase))).ToArray();
throw new ServiceException("标的数据未找到:" + string.Join(",", missingCode));
}
DateTime? maturityDate = null;
var underlying1 = underlyings.FirstOrDefault(n => ConsGlobal.InstrumentType.CalcTypeIsFutures(n.UnderlyingInstrumentType));
if (underlying1 == null)
{
underlying1 = underlyings.First();
}
else
{
maturityDate = underlyings.Where(n => ConsGlobal.InstrumentType.CalcTypeIsFutures(n.UnderlyingInstrumentType) && n.MaturityDate.HasValue)
.Min(n => n.MaturityDate);
}
underlying_manager underlying;
if (isAddNew)
{
underlying = new underlying_manager
{
UnderlyingCode = dbModel.UnderlyingTipsInfo,
MaturityDate = maturityDate,
UnderlyingState = "Live",
UnderlyingDesc = "组合标的",
OptId = dbModel.OptId,
OptName = dbModel.OptName,
OptDate = dbModel.OptDate,
CommodityCode = "组合标的",
UnderlyingType = "组合标的",
UnderlyingName = reqModel.Name,
UnderlyingInstrumentType = underlying1.UnderlyingInstrumentType,
Price = 0,
LaunchState = "1",
LastUpdateTime = dbModel.OptDate,
UnderlyingStatus = "正常运行",
VolatilityRate = reqModel.VolatilityRate,
UpDownLimit = reqModel.UpDownLimit,
MarginRate = reqModel.MarginRate,
ContractSize = reqModel.ContractSize ?? 0,
//----------------------------------
//2020/5/14 使用组合标的的第一个标的为新添加的字段赋值
//----------------------------------
TradeUnit = underlying1.TradeUnit,
QuoteUnit = underlying1.QuoteUnit,
MarketCode = underlying1.MarketCode,
MarketName = underlying1.MarketName,
OpenDate = DateTime.Today
};
if (string.IsNullOrWhiteSpace(underlying.TradeUnit))
{
underlying.TradeUnit = "份";
}
DbContext.underlying_manager.Add(underlying);
UpdateHisData(underlying, true);
}
else
{
var UnderlyingCodestr = dbModel.Name;
underlying = DbContext.underlying_manager.FirstOrDefault(u => u.UnderlyingCode == UnderlyingCodestr);
underlying.MaturityDate = maturityDate;
underlying.UnderlyingState = "Live";
underlying.UnderlyingInstrumentType = underlying1.UnderlyingInstrumentType;
underlying.Price = 0;
underlying.LaunchState = "1";
underlying.LastUpdateTime = dbModel.OptDate;
underlying.UnderlyingStatus = "正常运行";
underlying.VolatilityRate = reqModel.VolatilityRate;
underlying.UpDownLimit = reqModel.UpDownLimit;
underlying.MarginRate = reqModel.MarginRate;
underlying.ContractSize = reqModel.ContractSize ?? 0;
//----------------------------------
//2020/5/14 使用组合标的的第一个标的为新添加的字段赋值
//----------------------------------
underlying.TradeUnit = underlying1.TradeUnit;
underlying.QuoteUnit = underlying1.QuoteUnit;
underlying.MarketCode = underlying1.MarketCode;
underlying.MarketName = underlying1.MarketName;
underlying.UnderlyingName = reqModel.Name;
if (string.IsNullOrWhiteSpace(underlying.TradeUnit))
{
underlying.TradeUnit = "份";
}
UpdateHisData(underlying, false);
}
underlying.UnderlyingTypeId = UnderlyingHelper.GetSyntheticVariety().id;
DbContext.SaveChanges();
//----------------------------------
// 新增underlying_parameter
//----------------------------------
var underlying_params = DbContext.underlying_parameter.Where(u => u.UnderlyingId == underlying.id).ToList();
//如果没有报价参数,则新增
if (underlying_params.Count == 0)
{
underlying_parameter.defaultQuoteTypes.ForEach(t =>
{
var up = new underlying_parameter()
{
NoRiskRate = valuedateBLL.SystemDate.RiskFreeRate * 0.01,
Price = 0,
Gamma = 0,
Rho = 0,
Vega = 0,
Theta = 0,
Delta = 0,
UnderlyingId = underlying.id,
Type = t,
OptDate = DateTime.Now,
OptId = reqModel.OptId,
OptName = reqModel.OptName
};
DbContext.underlying_parameter.Add(up);
underlying_params.Add(up);
});
}
//最后调用保存以保证事物完整性
return DbContext.SaveChanges();
}
/// <summary>
/// 获取所有有效的组合标的
/// </summary>
public IEnumerable<SyntheticUnderlying> GetAllValidSyntheticUnderlyings()
{
var queryU = from u in DbContext.underlying_manager
where u.UnderlyingState != "Matured" && u.LaunchState == "1"
select new { u.id };
var date = DateTime.Today;
var query = from u in DbContext.underlying_manager
join su in DbContext.synthetic_underlying on u.UnderlyingCode equals su.Name
where u.MaturityDate >= date && u.UnderlyingType == "组合标的"
&& (su.UnderlyingId1 == null || su.UnderlyingId1 == 0 || queryU.Any(n => n.id == su.UnderlyingId1))
&& (su.UnderlyingId2 == null || su.UnderlyingId2 == 0 || queryU.Any(n => n.id == su.UnderlyingId2))
&& (su.UnderlyingId3 == null || su.UnderlyingId3 == 0 || queryU.Any(n => n.id == su.UnderlyingId3))
&& (su.UnderlyingId4 == null || su.UnderlyingId4 == 0 || queryU.Any(n => n.id == su.UnderlyingId4))
select su;
return query.ToArray();
}
/// <summary>
///
/// </summary>
public SyntheticUnderlyingDto GetSyntheticUnderlyingByName(string name)
{
var query = from u in DbContext.underlying_manager
join su in DbContext.synthetic_underlying on u.UnderlyingCode equals su.Name
where u.UnderlyingCode == name
select new SyntheticUnderlyingDto
{
id = su.id,
Coefficient1 = su.Coefficient1,
Coefficient2 = su.Coefficient2,
Coefficient3 = su.Coefficient3,
Coefficient4 = su.Coefficient4,
Constant = su.Constant,
ContractSize = su.ContractSize,
Name = su.Name,
OptDate = su.OptDate,
OptId = su.OptId,
OptName = su.OptName,
UnderlyingCode1 = su.UnderlyingCode1,
UnderlyingCode2 = su.UnderlyingCode2,
UnderlyingCode3 = su.UnderlyingCode3,
UnderlyingCode4 = su.UnderlyingCode4,
UnderlyingId1 = su.UnderlyingId1,
UnderlyingId2 = su.UnderlyingId2,
UnderlyingId3 = su.UnderlyingId3,
UnderlyingId4 = su.UnderlyingId4,
MarginRate = u.MarginRate,
UpDownLimit = u.UpDownLimit,
VolatilityRate = u.VolatilityRate,
UnderlyingName = u.UnderlyingName
};
return query.FirstOrDefault();
}
/// <summary>
/// 保存标的数据
/// </summary>
public underlying_manager SaveUnderlyingData(underlying_manager req)
{
if (string.IsNullOrWhiteSpace(req.UnderlyingCode))
{
throw new ServiceException("标的资产码 必须填写!");
}
if (string.IsNullOrWhiteSpace(req.UnderlyingName))
{
throw new ServiceException("标的名称 必须填写!");
}
if (string.IsNullOrWhiteSpace(req.UnderlyingInstrumentType))
{
throw new ServiceException("资产类型 必须填写!");
}
if (req.UnderlyingTypeId < 1)
{
throw new ServiceException("资产品种类型 必须填写!");
}
if (req.IsFutures())
{
if (!req.MaturityDate.HasValue)
{
throw new ServiceException("期货标的到期日期 必须填写!");
}
if (req.MaturityDate.Value.Year < 2000)
{
throw new ServiceException("期货标的到期日期 填写错误!");
}
if (req.MaturityDate.Value < DateTime.Today)
{
req.UnderlyingState = "Matured";
}
}
//if (DataCacheProvider.GetStockBlackWhiteDataSource().AsQueryable().Any(
// n => n.UnderlyingCode == req.UnderlyingCode && n.BlackWhiteState == 0))
//{
// throw new ServiceException("此标的存在于黑名单中,无法新增和修改");
//}
//判断是否重复标的
if (DbContext.underlying_manager.Any(d => d.UnderlyingCode == req.UnderlyingCode && d.id != req.id))
{
throw new ServiceException("标的资产码重复");
}
underlying_manager dbModel;
var isNew = req.id == 0;
if (isNew)
{
dbModel = req;
if (typeof(underlying_manager) != req.GetType())
{
dbModel = new underlying_manager();
ObjectHelper.MapValues(dbModel, req);
}
dbModel.Price = underlying_manager.DefaultSpotPrice;
// 新增标的默认启用
dbModel.LaunchState = "1";
DbContext.underlying_manager.Add(dbModel);
}
else
{
dbModel = DbContext.underlying_manager.Find(req.id);
if (dbModel == null)
{
throw new ServiceException("保存失败,数据不存在");
}
UpdateChanges(dbModel, req, new[] {
nameof(underlying_manager.id) ,
//nameof(underlying_manager.Price) ,
nameof(underlying_manager.PrevClosePrice) ,
nameof(underlying_manager.LaunchState) ,
nameof(underlying_manager.LastUpdateTime)
});
}
dbModel.OptId = UserId;
dbModel.OptName = UserName;
dbModel.OptDate = DateTime.Now;
//更新关联表
var variety = DbContext.variety.Find(dbModel.UnderlyingTypeId);
if (variety != null)
{
dbModel.UnderlyingType = variety.VarietyName;
dbModel.CommodityCode = variety.VarietyCode;
dbModel.QuoteUnit = variety.QuoteUnitSingleOriginal;
dbModel.TradeUnit = variety.TradeUnitSingle;
if (string.IsNullOrWhiteSpace(req.MarketCode))
{
dbModel.MarketName = variety.TradingMarket;
dbModel.MarketCode = string.IsNullOrWhiteSpace(dbModel.MarketName) ? "" :
DataCacheProvider.GetMarketDataSource().AsQueryable().FirstOrDefault(n => n.MarketName == dbModel.MarketName)?.ExchangeNo;
}
if (dbModel.ContractSize <= 1)
{
dbModel.ContractSize = variety.TradeUnitValue > 0 ? variety.TradeUnitValue.Value : 1;
}
if (dbModel.PriceTick < 1e-5)
{
dbModel.PriceTick = VarietyHelper.ParseMinPriceChange(variety.MinPriceChange) ?? 0.01;
}
}
if (!string.IsNullOrWhiteSpace(req.MarketCode))
{
dbModel.MarketName = string.IsNullOrWhiteSpace(dbModel.MarketCode) ? "" :
DataCacheProvider.GetMarketDataSource().AsQueryable().FirstOrDefault(n => n.ExchangeNo == dbModel.MarketCode)?.MarketName;
}
if (dbModel.CalcTypeIsStock())
{
dbModel.MaturityDate = null;
}
UpdateHisData(req, isNew);
DbContext.SaveChanges();
new DicForTranslationModule.DicForTranslationService(OptUser).SetWordDictionary(req);
return dbModel;
}
/// <summary>
/// 保存标的数据
/// </summary>
public IEnumerable<underlying_manager> SaveUnderlyingData(IEnumerable<underlying_manager> reqs)
{
if (reqs.Any(O => string.IsNullOrWhiteSpace(O.UnderlyingCode)))
{
throw new ServiceException("标的资产码 必须填写!");
}
if (reqs.Any(O => string.IsNullOrWhiteSpace(O.UnderlyingName)))
{
throw new ServiceException("标的名称 必须填写!");
}
if (reqs.Any(O => string.IsNullOrWhiteSpace(O.UnderlyingInstrumentType)))
{
throw new ServiceException("资产类型 必须填写!");
}
if (reqs.Any(O => O.UnderlyingTypeId < 1))
{
throw new ServiceException("资产品种类型 必须填写!");
}
if (reqs.Any(O => O.IsFutures() && !O.MaturityDate.HasValue))
{
throw new ServiceException("期货标的到期日期 必须填写!");
}
if (reqs.Any(O => O.IsFutures() && O.MaturityDate.Value.Year < 2000))
{
throw new ServiceException("期货标的到期日期 填写错误!");
}
if (reqs.Where(O => O.IsFutures() && O.MaturityDate.Value < DateTime.Today).ToList() is List<underlying_manager> um)
{
um.ForEach(O => O.UnderlyingState = "Matured");
}
List<string> underlyingCode_New = reqs.Where(O => O.id < 1).Select(O => O.UnderlyingCode).ToList();
if (DataCacheProvider.GetStockBlackWhiteDataSource().AsQueryable().Any(
n => underlyingCode_New.Contains(n.UnderlyingCode) && n.BlackWhiteState == 0))
{
throw new ServiceException("此标的存在于黑名单中,无法新增和修改");
}
//判断是否重复标的
if (underlyingCode_New.Distinct().Count() != underlyingCode_New.Count || DbContext.underlying_manager.Any(d => underlyingCode_New.Contains(d.UnderlyingCode)))
{
throw new ServiceException("标的资产码重复");
}
foreach (var req in reqs)
{
underlying_manager dbModel;
var isNew = req.id == 0;
if (isNew)
{
dbModel = req;
dbModel.Price = underlying_manager.DefaultSpotPrice;
DbContext.underlying_manager.Add(dbModel);
}
else
{
dbModel = DbContext.underlying_manager.Find(req.id);
if (dbModel == null)
{
throw new ServiceException("保存失败,数据不存在");
}
UpdateChanges(dbModel, req, new[] {
nameof(underlying_manager.id) ,
nameof(underlying_manager.Price) ,
nameof(underlying_manager.PrevClosePrice) ,
nameof(underlying_manager.LaunchState) ,
nameof(underlying_manager.LastUpdateTime)
});
}
dbModel.OptId = UserId;
dbModel.OptName = UserName;
dbModel.OptDate = DateTime.Now;
dbModel.MarketName = string.IsNullOrWhiteSpace(dbModel.MarketCode) ? "" :
DataCacheProvider.GetMarketDataSource().AsQueryable().FirstOrDefault(n => n.ExchangeNo == dbModel.MarketCode)?.MarketName;
//更新关联表
var variety = DataCacheProvider.GetVarietyDataSource().GetData(dbModel.UnderlyingTypeId);
if (variety != null)
{
dbModel.UnderlyingType = variety.VarietyName;
dbModel.CommodityCode = variety.VarietyCode;
dbModel.QuoteUnit = variety.QuoteUnitSingleOriginal;
dbModel.TradeUnit = variety.TradeUnitSingle;
if (dbModel.ContractSize <= 1)
{
dbModel.ContractSize = variety.TradeUnitValue ?? 0;
}
if (dbModel.PriceTick < 1e-5)
{
dbModel.PriceTick = VarietyHelper.ParseMinPriceChange(variety.MinPriceChange) ?? 0.01;
}
}
if (dbModel.CalcTypeIsStock())
{
dbModel.MaturityDate = null;
}
UpdateHisData(req, isNew);
}
DbContext.SaveChanges();
return reqs;
}
/// <summary>
/// 保存标的历史数据
/// </summary>
private void UpdateHisData(underlying_manager newData, bool isNewUnderlying)
{
var newPara = MarginParamModel.Create(newData.MarginRate, newData.VolatilityRate, newData.UpDownLimit, true);
if (!string.IsNullOrWhiteSpace(newData.VolatilityRate) && !newPara.VolatilityRate.HasValue)
{
throw new ServiceException("解析Span波动率变动失败:" + newData.VolatilityRate);
}
if (!string.IsNullOrWhiteSpace(newData.UpDownLimit) && !newPara.UpDownLimit.HasValue)
{
throw new ServiceException("解析Span涨跌幅度失败:" + newData.UpDownLimit);
}
if (isNewUnderlying)
{
DbContext.BulkDelete<UnderlyingHisData>($"{nameof(UnderlyingHisData.UnderlyingCode)}='{newData.UnderlyingCode}'");
}
var hisdataService = new UnderlyingHisDataService(this);
var valdate = isNewUnderlying ? new DateTime(2000, 1, 1) : valuedateBLL.ValueDate;
hisdataService.AddOrUpdateHisData(new UnderlyingHisDataAddOrUpdateRequest
{
UnderlyingCode = newData.UnderlyingCode,
ValueType = nameof(MarginParamModel.MarginRate),
Value = newPara.MarginRate,
ValueDate = valdate,
ValueFlag = "F"
}, false);
hisdataService.AddOrUpdateHisData(new UnderlyingHisDataAddOrUpdateRequest
{
UnderlyingCode = newData.UnderlyingCode,
ValueType = nameof(MarginParamModel.VolatilityRate),
Value = newPara.VolatilityRate,
ValueDate = valdate,
ValueFlag = "F"
}, false);
hisdataService.AddOrUpdateHisData(new UnderlyingHisDataAddOrUpdateRequest
{
UnderlyingCode = newData.UnderlyingCode,
ValueType = nameof(MarginParamModel.UpDownLimit),
Value = newPara.UpDownLimit,
ValueDate = valdate,
ValueFlag = newPara.IsUpDownLimitFixed ? "F" : "%"
}, false);
}
/// <summary>
/// 更新数据
/// </summary>
public int UpdateData(string UnderlyingCode, double? MarginRate, string VolatilityRate, string UpDownLimit)
{
if (UnderlyingCode is null)
{
throw new ArgumentNullException(nameof(UnderlyingCode));
}
var underlying = DbContext.underlying_manager.FirstOrDefault(u => u.UnderlyingCode == UnderlyingCode);
if (underlying == null)
{
throw new ServiceException("系统中没有相关的标的:" + UnderlyingCode);
}
if (underlying.IsSynthetic())
{
underlying.UnderlyingTypeId = UnderlyingHelper.GetSyntheticVariety().id;
}
underlying.MarginRate = MarginRate;
underlying.VolatilityRate = VolatilityRate;
underlying.UpDownLimit = UpDownLimit;
UpdateHisData(underlying, false);
return DbContext.SaveChanges();
}
/// <summary>
/// 删除合成标的
/// </summary>
public int RemoveSyntheticUnderlyingByName(string syntheticUnderlyingName)
{
if (syntheticUnderlyingName is null)
{
throw new ArgumentNullException(nameof(syntheticUnderlyingName));
}
if (DbContext.trade.Any(trade => trade.UnderlyingCode == syntheticUnderlyingName && trade.ValidState != ConsGlobal.InValid))
{
throw new ServiceException("系统存在使用此组合标的的交易,不能修改");
}
var synModel = DbContext.synthetic_underlying.FirstOrDefault(n => n.Name == syntheticUnderlyingName);
var unModel = DbContext.underlying_manager.FirstOrDefault(n => n.UnderlyingCode == syntheticUnderlyingName);
if (unModel != null)
{
DbContext.underlying_manager.Remove(unModel);
}
if (synModel != null)
{
DbContext.synthetic_underlying.Remove(synModel);
}
return DbContext.SaveChanges();
}
}
}