- 在ConsGlobal中为所有标的类型常量添加中文注释说明 - 新增UseStockPriceTable方法用于判断标的类型是否使用股票价格表 - 修改SettlementPriceImportService中的价格表分流逻辑 - 添加单元测试验证股指期货、基金等进入股票价格表的逻辑 - 确保Shibor、利率收益率和债券指数进入正确的商品期货价格表
251 lines
9.9 KiB
C#
251 lines
9.9 KiB
C#
using System.Data;
|
||
using YLErp.Commons;
|
||
using YLErp.Model;
|
||
|
||
namespace YLErp.Modules.EodModule
|
||
{
|
||
/// <summary>
|
||
/// 结算价导入服务
|
||
/// </summary>
|
||
public class SettlementPriceImportService : YLBaseService
|
||
{
|
||
public SettlementPriceImportService(OptUserInfo userInfo) : base(userInfo)
|
||
{
|
||
|
||
}
|
||
|
||
public static bool UseStockPriceTable(string instrumentType)
|
||
{
|
||
return ConsGlobal.InstrumentType.EquityTypes().Contains(instrumentType)
|
||
|| instrumentType == ConsGlobal.InstrumentType.Fund;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 导入xlsx数据
|
||
/// </summary>
|
||
public ImportResultModel ImportxlsxDatas(Stream stream)
|
||
{
|
||
var importModels = Enumerable.Empty<ImportModel>();
|
||
var rowIndex = 0;
|
||
|
||
try
|
||
{
|
||
var ds = Office.ExcelHelper.ReadExcelAsDataSet(stream);
|
||
|
||
if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 1)
|
||
{
|
||
throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" };
|
||
}
|
||
|
||
var table = ds.Tables[0];
|
||
var reader = new DataRowReader(table);
|
||
|
||
var list = new List<ImportModel>();
|
||
|
||
rowIndex = 1;
|
||
|
||
foreach (DataRow row in table.Rows)
|
||
{
|
||
rowIndex++;
|
||
|
||
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
reader.SetDataRow(row);
|
||
|
||
var model = new ImportModel
|
||
{
|
||
date = reader.GetDate("日期", true).Value,
|
||
code = reader.GetString("代码", true),
|
||
closePrice = reader.GetDouble("收盘价", false),
|
||
settlePrice = reader.GetDouble("结算价", false),
|
||
ReferencePrice = reader.GetDouble("参考价", false)
|
||
};
|
||
|
||
model.underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(model.code);
|
||
|
||
if (model.underlying == null)
|
||
{
|
||
throw new ServiceException("标的代码不存在:" + model.code) { Tag = "111" };
|
||
}
|
||
|
||
list.Add(model);
|
||
}
|
||
|
||
importModels = list.ToArray();
|
||
}
|
||
catch (ServiceException se)
|
||
{
|
||
if (se.Tag != null) throw;
|
||
throw new ServiceException($"第{rowIndex}行,发生错误:{se.Message}");
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
LogFactory.GetLogger("导入场内交易").Error(ex);
|
||
throw new ServiceException($"第{rowIndex}行,发生错误:{ex.Message}", ex);
|
||
}
|
||
|
||
if (!importModels.Any())
|
||
{
|
||
throw new ServiceException("没有可导入的数据");
|
||
}
|
||
|
||
var result = new ImportResultModel
|
||
{
|
||
TotalCount = importModels.Count()
|
||
};
|
||
|
||
var dates = new HashSet<DateTime>();
|
||
var uniqSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||
|
||
foreach (var item in importModels)
|
||
{
|
||
var underlying = item.underlying;
|
||
if (underlying.IsBond())
|
||
{
|
||
var eodPrice = DbContext.china_bond_valuation
|
||
.FirstOrDefault(p => p.valuation_date == item.date && p.bond_id == underlying.UnderlyingCode);
|
||
|
||
if (eodPrice == null)
|
||
{
|
||
var datestr = item.date.ToString("yyyyMMdd");
|
||
|
||
if (uniqSet.Add(datestr + "^" + item.code))
|
||
{
|
||
eodPrice = new ChinaBondValuation();
|
||
eodPrice.credibility = 1;
|
||
DbContext.china_bond_valuation.Add(eodPrice);
|
||
}
|
||
else
|
||
{
|
||
result.Errors.Add($"重复数据,忽略: {datestr},{item.code}");
|
||
continue;
|
||
}
|
||
}
|
||
|
||
eodPrice.valuation_date = item.date;
|
||
eodPrice.bond_id = underlying.UnderlyingCode;
|
||
if (item.closePrice.HasValue)
|
||
eodPrice.dirty_price_close =Convert.ToDecimal(item.closePrice ?? 0);
|
||
if (item.settlePrice.HasValue)
|
||
eodPrice.net_price = Convert.ToDecimal(item.settlePrice ?? 0);
|
||
if (item.ReferencePrice.HasValue)
|
||
eodPrice.yield = Convert.ToDecimal(item.ReferencePrice);
|
||
eodPrice.update_time = DateTime.Now;
|
||
// 手工上传也是登录用户的人工动作,戳操作人到已有列(create_user/update_user),
|
||
// 使列表来源列显示上传人姓名(与 SaveBondPrice 口径一致);聚源/中债自动同步(外部ETL)不写这两列。
|
||
// eodPrice.id==0 表示本次新增(尚未落库),非0为命中已有行的更新。
|
||
EodPriceService.StampBondOperator(eodPrice, UserId, eodPrice.id == 0);
|
||
result.SuccessCount++;
|
||
}
|
||
else if (!UseStockPriceTable(underlying.UnderlyingInstrumentType))
|
||
{
|
||
var eodPrice = DbContext.eod_commodity_future_price
|
||
.FirstOrDefault(p => p.ValueDate == item.date && p.UnderlyingCode == underlying.UnderlyingCode);
|
||
|
||
if (eodPrice == null)
|
||
{
|
||
var datestr = item.date.ToString("yyyyMMdd");
|
||
|
||
if (uniqSet.Add(datestr + "^" + item.code))
|
||
{
|
||
eodPrice = new eod_commodity_future_price();
|
||
DbContext.eod_commodity_future_price.Add(eodPrice);
|
||
}
|
||
else
|
||
{
|
||
result.Errors.Add($"重复数据,忽略: {datestr},{item.code}");
|
||
continue;
|
||
}
|
||
}
|
||
|
||
eodPrice.ValueDate = item.date;
|
||
eodPrice.UnderlyingCode = underlying.UnderlyingCode;
|
||
eodPrice.UnderlyingId = underlying.id;
|
||
// 入库前强制 UnderlyingId 与 UnderlyingCode(FutureContractId) 一致,避免网页/结算两套 JOIN 失同步。
|
||
EodPriceService.SyncUnderlyingIdFromCode(DbContext, eodPrice);
|
||
if (item.closePrice.HasValue)
|
||
eodPrice.ClosePrice = item.closePrice ?? 0;
|
||
if (item.settlePrice.HasValue)
|
||
eodPrice.SettlePrice = item.settlePrice ?? 0;
|
||
if (item.ReferencePrice.HasValue)
|
||
eodPrice.ReferencePrice = item.ReferencePrice;
|
||
eodPrice.OptId = UserId;
|
||
eodPrice.OptName = UserName;
|
||
eodPrice.OptDate = DateTime.Now;
|
||
eodPrice.DataSource = EodPriceBase.人工;
|
||
result.SuccessCount++;
|
||
}
|
||
else
|
||
{
|
||
var stockPrice = DbContext.eod_stock_price
|
||
.FirstOrDefault(p => p.ValueDate == item.date && p.UnderlyingCode == underlying.UnderlyingCode);
|
||
|
||
if (stockPrice == null)
|
||
{
|
||
var datestr = item.date.ToString("yyyyMMdd");
|
||
|
||
if (uniqSet.Add(datestr + "^" + item.code))
|
||
{
|
||
stockPrice = new eod_stock_price();
|
||
DbContext.eod_stock_price.Add(stockPrice);
|
||
}
|
||
else
|
||
{
|
||
result.Errors.Add($"重复数据,忽略: {datestr},{item.code}");
|
||
continue;
|
||
}
|
||
}
|
||
|
||
stockPrice.ValueDate = item.date;
|
||
stockPrice.UnderlyingCode = underlying.UnderlyingCode;
|
||
if (item.closePrice.HasValue)
|
||
stockPrice.ClosePrice = item.closePrice ?? 0;
|
||
if (item.ReferencePrice.HasValue)
|
||
stockPrice.ReferencePrice = item.ReferencePrice;
|
||
stockPrice.OptDate = DateTime.Now;
|
||
stockPrice.DataSource = EodPriceBase.人工;
|
||
result.SuccessCount++;
|
||
}
|
||
//else
|
||
//{
|
||
// result.Errors.Add("未导入,标的不属于商品或股票:" + item.code);
|
||
//}
|
||
|
||
dates.Add(item.date.Date);
|
||
}
|
||
|
||
DbContext.SaveChanges();
|
||
|
||
if (dates.Contains(BLL.valuedateBLL.ValueDate))
|
||
{
|
||
var sql = $@"
|
||
update underlying_manager um join eod_commodity_future_price eod on um.UnderlyingCode = eod.FutureContractId
|
||
set um.Price = eod.ClosePrice where eod.ValueDate='{BLL.valuedateBLL.ValueDate:yyyy-MM-dd}';
|
||
update underlying_manager um join eod_stock_price eod on um.UnderlyingCode = eod.StockId
|
||
set um.Price = eod.ClosePrice where eod.ValueDate='{BLL.valuedateBLL.ValueDate:yyyy-MM-dd}';";
|
||
DbContext.Database.ExecuteSqlRaw(sql);
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
class ImportModel
|
||
{
|
||
public DateTime date { get; set; }
|
||
|
||
public string code { get; set; }
|
||
|
||
public double? closePrice { get; set; }
|
||
|
||
public double? settlePrice { get; set; }
|
||
|
||
public double? ReferencePrice { get; set; }
|
||
|
||
public underlying_manager underlying { get; set; }
|
||
}
|
||
}
|
||
}
|