从山证v2.3.0拷贝
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
namespace YLErp.Modules.UnderlyingModule.ApiModudle
|
||||
{
|
||||
/// <summary>
|
||||
/// API数据检索服务
|
||||
/// </summary>
|
||||
public class ApiDataQueryService : YLBaseService
|
||||
{
|
||||
public ApiDataQueryService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public IEnumerable<ApiUnderlyingInfo> GetUnderlyingList()
|
||||
{
|
||||
var date = DateTime.Now.AddMonths(-3);
|
||||
var underlyings = DbContext.underlying_manager.AsNoTracking()
|
||||
.Where(n => n.UnderlyingInstrumentType != "CommodityFutures" || n.MaturityDate > date)
|
||||
.Select(n => new
|
||||
{
|
||||
n.UnderlyingCode,
|
||||
n.ContractSize,
|
||||
n.UnderlyingInstrumentType,
|
||||
n.UnderlyingName,
|
||||
n.MarketCode,
|
||||
n.CommodityCode,
|
||||
n.MaturityDate,
|
||||
n.PriceTick,
|
||||
n.MarginRate,
|
||||
n.OpenDate,
|
||||
n.UpDownLimit,
|
||||
n.VolatilityRate,
|
||||
n.UnderlyingTypeId
|
||||
|
||||
}).ToList();
|
||||
|
||||
var varietyDic = DbContext.variety.Select(n => new { n.id, n.VolatilityRate, n.UpLimit, n.Margin }).ToDictionary(n => n.id);
|
||||
|
||||
return underlyings.Select(x =>
|
||||
{
|
||||
var contractSize = x.ContractSize;
|
||||
var contractType = UnderlyingContractTypeEnum.None;
|
||||
switch (x.UnderlyingInstrumentType)
|
||||
{
|
||||
case "Stock":
|
||||
contractSize = 100;
|
||||
contractType = UnderlyingContractTypeEnum.Stocks;
|
||||
break;
|
||||
case "CommodityFutures":
|
||||
contractType = UnderlyingContractTypeEnum.Futures;
|
||||
break;
|
||||
case "CommoditySpot":
|
||||
contractType = UnderlyingContractTypeEnum.Spot;
|
||||
break;
|
||||
}
|
||||
|
||||
var marginRate = x.MarginRate;
|
||||
|
||||
double? volatilitySpan = null, updownLimit = null;
|
||||
|
||||
bool isUpdownFixed = false;
|
||||
|
||||
if (NumberHelper.TryParse(x.VolatilityRate, out var dvalue, out bool isPercent))
|
||||
{
|
||||
volatilitySpan = dvalue;
|
||||
}
|
||||
|
||||
if (NumberHelper.TryParse(x.UpDownLimit, out dvalue, out isPercent))
|
||||
{
|
||||
updownLimit = dvalue;
|
||||
isUpdownFixed = !isPercent;
|
||||
}
|
||||
|
||||
//如果标的的几个幅度没有则取品种的
|
||||
if (varietyDic.TryGetValue(x.UnderlyingTypeId, out var va))
|
||||
{
|
||||
if (!marginRate.HasValue)
|
||||
{
|
||||
marginRate = va.Margin;
|
||||
}
|
||||
|
||||
if (!volatilitySpan.HasValue && NumberHelper.TryParse(va.VolatilityRate, out dvalue, out isPercent))
|
||||
{
|
||||
volatilitySpan = dvalue;
|
||||
}
|
||||
|
||||
if (!updownLimit.HasValue && NumberHelper.TryParse(va.UpLimit, out dvalue, out isPercent))
|
||||
{
|
||||
updownLimit = dvalue;
|
||||
isUpdownFixed = false;
|
||||
}
|
||||
}
|
||||
|
||||
return new ApiUnderlyingInfoEx
|
||||
{
|
||||
Code = x.UnderlyingCode,
|
||||
Name = x.UnderlyingName,
|
||||
Exchange = x.MarketCode,
|
||||
Product_Class = x.CommodityCode,
|
||||
Expire_Date = x.MaturityDate?.ToString("yyyy-MM-dd"),
|
||||
Multiple = contractSize,
|
||||
Price_Tick = x.PriceTick,
|
||||
Long_Margin_Ratio = x.MarginRate ?? 0,
|
||||
Short_Margin_Ratio = x.MarginRate ?? 0,
|
||||
Contract_Type = contractType,
|
||||
Create_Date = x.OpenDate?.ToString("yyyy-MM-dd"),
|
||||
OptionType = OptionTypeEnum.None,
|
||||
Underlying_Code = "",
|
||||
MarginRate = marginRate ?? 0,
|
||||
IsUpdownLimitFixed = isUpdownFixed,
|
||||
UpdownLimit = updownLimit ?? 0,
|
||||
VolatilitySpan = volatilitySpan ?? 0
|
||||
};
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
public IEnumerable<ApiUnderlyingInfo> GetExchangeOptionList()
|
||||
{
|
||||
var date = DateTime.Now.AddMonths(-1);
|
||||
|
||||
var exchangeOptions = DbContext.exchange_list_option.Where(x => x.MaturityDate >= date).ToList();
|
||||
|
||||
return exchangeOptions.Select(x =>
|
||||
{
|
||||
return new ApiUnderlyingInfo
|
||||
{
|
||||
Code = x.ContractCode,
|
||||
Underlying_Code = x.UnderlyingCode,
|
||||
Exchange = x.MarketCode,
|
||||
Create_Date = x.OpenDate?.ToString("yyyy-MM-dd") ?? "",
|
||||
Expire_Date = x.MaturityDate.ToString("yyyy-MM-dd"),
|
||||
Strike = x.Strike,
|
||||
Contract_Type = UnderlyingContractTypeEnum.Options,
|
||||
OptionType = x.OptionType == "看涨" ? OptionTypeEnum.Call : OptionTypeEnum.Put,
|
||||
Long_Margin_Ratio = x.MarginRate ?? 0,
|
||||
Short_Margin_Ratio = x.MarginRate ?? 0,
|
||||
Multiple = x.ContractSize,
|
||||
Name = string.Empty,
|
||||
Price_Tick = x.PriceTick,
|
||||
Product_Class = string.Empty
|
||||
};
|
||||
}).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule.ApiModudle
|
||||
{
|
||||
public class ApiUnderlyingInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 合约代码UnderlyingCode,(场内期权则是场内期权代码 Exchange_list_option表中对应contractcode)
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 合约名称(场内期权忽略) UnderlyingName
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易所代码(MarketCode)
|
||||
/// </summary>
|
||||
public string Exchange { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 产品种类 CommodityCode(场内期权忽略)
|
||||
/// </summary>
|
||||
public string Product_Class { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 场内期权字段--场内期权的标的代码,其它忽略
|
||||
/// </summary>
|
||||
public string Underlying_Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 上市日期
|
||||
/// </summary>
|
||||
public string Create_Date { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 到期日期
|
||||
/// </summary>
|
||||
public string Expire_Date { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 合约乘数
|
||||
/// </summary>
|
||||
public double Multiple { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 行权价(场内期权产品用,其它 0)
|
||||
/// </summary>
|
||||
public double Strike { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 最小变动价位 来自品种表
|
||||
/// </summary>
|
||||
public double Price_Tick { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 多头预付金率,MarginRate
|
||||
/// </summary>
|
||||
public double Long_Margin_Ratio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 空投预付金率,MarginRate
|
||||
/// </summary>
|
||||
public double Short_Margin_Ratio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易产品类型
|
||||
/// </summary>
|
||||
public UnderlyingContractTypeEnum Contract_Type { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 期权类型
|
||||
/// </summary>
|
||||
public OptionTypeEnum OptionType { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Code}--{Name}--{Multiple}";
|
||||
}
|
||||
}
|
||||
|
||||
public class ApiUnderlyingInfoEx : ApiUnderlyingInfo
|
||||
{
|
||||
/// <summary>
|
||||
/// 预付金比率
|
||||
/// </summary>
|
||||
public double MarginRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 波动率变动幅度
|
||||
/// </summary>
|
||||
public double VolatilitySpan { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 涨跌停幅度
|
||||
/// </summary>
|
||||
public double UpdownLimit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 涨跌停幅度是否固定值
|
||||
/// </summary>
|
||||
public bool IsUpdownLimitFixed { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Code}--{MarginRate}--{UpdownLimit}--{IsUpdownLimitFixed}--{VolatilitySpan}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public enum UnderlyingContractTypeEnum
|
||||
{
|
||||
None = 0,
|
||||
|
||||
/// <summary>
|
||||
/// 现货
|
||||
/// </summary>
|
||||
Spot = 1,
|
||||
|
||||
/// <summary>
|
||||
/// 期货
|
||||
/// </summary>
|
||||
Futures = 2,
|
||||
|
||||
/// <summary>
|
||||
/// 证券
|
||||
/// </summary>
|
||||
Stocks = 3,
|
||||
|
||||
/// <summary>
|
||||
/// 期货期权
|
||||
/// </summary>
|
||||
Options = 4,
|
||||
|
||||
/// <summary>
|
||||
/// 股票期权
|
||||
/// </summary>
|
||||
StockOptions = 5,
|
||||
|
||||
/// <summary>
|
||||
/// 现货期权
|
||||
/// </summary>
|
||||
SpotOption = 6,
|
||||
|
||||
/// <summary>
|
||||
/// 期转现
|
||||
/// </summary>
|
||||
FutuToSpot = 7,
|
||||
|
||||
/// <summary>
|
||||
/// 组合
|
||||
/// </summary>
|
||||
Combination = 8,
|
||||
|
||||
/// <summary>
|
||||
/// 外汇远期
|
||||
/// </summary>
|
||||
FxForward = 9,
|
||||
|
||||
/// <summary>
|
||||
/// 金交所递延
|
||||
/// </summary>
|
||||
SGE_DEFER = 10,
|
||||
|
||||
/// <summary>
|
||||
/// 金交所远期
|
||||
/// </summary>
|
||||
SGE_FOWARD = 11,
|
||||
|
||||
/// <summary>
|
||||
/// 金交所现货
|
||||
/// </summary>
|
||||
SGE_SPOT = 12,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public enum OptionTypeEnum
|
||||
{
|
||||
None = 0,
|
||||
Call = 1,
|
||||
Put = 2
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
using YLErp.Abstract.DataProviders;
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 篮子标的帮助类
|
||||
/// </summary>
|
||||
public static class BasketUnderlyingHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取篮子标的价格
|
||||
/// </summary>
|
||||
public static BasketPriceResult GetBasketPrice(underlying_manager basketUnderlying,
|
||||
IBasketPriceProvider priceProvider, bool ignoreError)
|
||||
{
|
||||
if (basketUnderlying is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(basketUnderlying));
|
||||
}
|
||||
|
||||
if (!basketUnderlying.IsBasket())
|
||||
{
|
||||
return new BasketPriceResult();
|
||||
}
|
||||
|
||||
return GetBasketPrice(basketUnderlying.SubData, priceProvider, ignoreError);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取篮子标的价格
|
||||
/// </summary>
|
||||
public static BasketPriceResult GetBasketPrice(string subData, IBasketPriceProvider priceProvider, bool ignoreError)
|
||||
{
|
||||
var result = new BasketPriceResult();
|
||||
|
||||
var list = JsonHelper.Deserialize<List<BasketUnderlyingItem>>(subData);
|
||||
|
||||
if (list == null || !list.Any())
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
double weight = 0;
|
||||
|
||||
foreach (var item in list)
|
||||
{
|
||||
weight += item.weight;
|
||||
|
||||
if (priceProvider.TryGetSubPrice(item.code, out var price, out var settlePrice))
|
||||
{
|
||||
result.Price += item.weight * price;
|
||||
result.SettlePrice += item.weight * settlePrice;
|
||||
}
|
||||
else if (!ignoreError)
|
||||
{
|
||||
if (result.ErrorCodeList == null)
|
||||
{
|
||||
result.ErrorCodeList = new List<string>();
|
||||
}
|
||||
result.ErrorCodeList.Add(item.code);
|
||||
}
|
||||
}
|
||||
|
||||
if (weight > 0)
|
||||
{
|
||||
result.Price /= weight;
|
||||
result.SettlePrice /= weight;
|
||||
}
|
||||
else
|
||||
{
|
||||
result.Price = result.SettlePrice = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取篮子标的价格结果
|
||||
/// </summary>
|
||||
public struct BasketPriceResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 行情价或收盘价
|
||||
/// </summary>
|
||||
public double Price;
|
||||
|
||||
/// <summary>
|
||||
/// 结算价
|
||||
/// </summary>
|
||||
public double SettlePrice;
|
||||
|
||||
/// <summary>
|
||||
/// 未找到价格的标的代码集合
|
||||
/// </summary>
|
||||
public List<string> ErrorCodeList;
|
||||
|
||||
/// <summary>
|
||||
/// 是否存在未找到价格的标的代码集合
|
||||
/// </summary>
|
||||
public bool HasError => ErrorCodeList != null && ErrorCodeList.Any();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Data;
|
||||
using YLErp.BLL;
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 篮子标的信息管理服务
|
||||
/// </summary>
|
||||
public class BasketUnderlyingService : YLBaseService
|
||||
{
|
||||
public BasketUnderlyingService(YLBaseService baseService) : base(baseService)
|
||||
{
|
||||
}
|
||||
|
||||
public BasketUnderlyingService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 组合标的导入xlsx数据
|
||||
/// </summary>
|
||||
public BasketUnderlyingDto ImportBasketDatasFromExcel(Stream stream)
|
||||
{
|
||||
var result = new BasketUnderlyingDto();
|
||||
try
|
||||
{
|
||||
//当前编码支持ansi和utf with bom
|
||||
|
||||
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];
|
||||
List<BasketUnderlyingItem> list = new List<BasketUnderlyingItem>();
|
||||
if (table.Rows.Count < 1)
|
||||
{
|
||||
throw new ServiceException("导入数据不能为空!");
|
||||
}
|
||||
var useWhiteCode = new StockBlackWhiteService(UserInfo).GetStockBlackWhiteList(Configuration.Enums.LimitRangeEnum.Swap, out var Codes);
|
||||
foreach (DataRow row in table.Rows)
|
||||
{
|
||||
if (row.IsNull("标的代码") || row.IsNull("标的权重"))
|
||||
{
|
||||
throw new ServiceException("导入标的代码或标的权重不能为空!");
|
||||
}
|
||||
double price = 0;
|
||||
BasketUnderlyingItem importModel = new BasketUnderlyingItem();
|
||||
importModel.code = (string)row["标的代码"];
|
||||
double.TryParse((row["标的权重"]?.ToString() ?? ""), out var weight);
|
||||
importModel.weight = weight;
|
||||
double.TryParse((row["标的份额"]?.ToString() ?? ""), out var notional);
|
||||
importModel.notional = notional;
|
||||
DataCacheProvider.GetUnderlyingDataSource().TryGetPrice(importModel.code, out price);
|
||||
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(importModel.code);
|
||||
if (underlying == null)
|
||||
{
|
||||
throw new ServiceException("标的代码不存在: " + importModel.code);
|
||||
}
|
||||
if (ConsGlobal.InstrumentType.IsStock(underlying.UnderlyingInstrumentType) && Codes != null && useWhiteCode == Codes.Contains(importModel.code))
|
||||
{
|
||||
throw new ServiceException($"标的代码:{importModel.code} {(useWhiteCode ? "存在于黑名单中" : "不在白名单中")}");
|
||||
}
|
||||
importModel.Price = price;
|
||||
list.Add(importModel);
|
||||
}
|
||||
result.Items = list;
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
throw (ex.InnerException as ServiceException) ?? ex;
|
||||
}
|
||||
|
||||
|
||||
if (!result.Items.Any())
|
||||
{
|
||||
throw new ServiceException("没有可导入的数据");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存篮子标的数据
|
||||
/// </summary>
|
||||
public int SaveBasketUnderlying(BasketUnderlyingDto model)
|
||||
{
|
||||
if (model is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(model));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(model.UnderlyingCode))
|
||||
{
|
||||
throw new ServiceException("别名不能为空");
|
||||
}
|
||||
|
||||
if (DbContext.underlying_manager.Any(n => n.UnderlyingCode == model.UnderlyingCode))
|
||||
{
|
||||
throw new ServiceException("系统中已有重名的组合标的");
|
||||
}
|
||||
|
||||
if (model.Items == null || !model.Items.Any())
|
||||
{
|
||||
throw new ServiceException("篮子标的列表没有任何数据");
|
||||
}
|
||||
|
||||
if (model.Items.Any(n => string.IsNullOrWhiteSpace(n.code)))
|
||||
{
|
||||
throw new ServiceException("篮子标的列表中不应存在空白标的");
|
||||
}
|
||||
|
||||
var isAddNew = model.id <= 0;
|
||||
|
||||
//----------------------------------
|
||||
// 存入underlying_manager表
|
||||
//----------------------------------
|
||||
|
||||
var variety = UnderlyingHelper.GetBasketVariety();
|
||||
|
||||
//----------------------------------
|
||||
// 2020/5/14 获取组合标的的第一个标的
|
||||
//----------------------------------
|
||||
|
||||
var underlyingCode1 = model.Items.First().code;
|
||||
var underlying1 = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode1);
|
||||
if (underlying1 == null)
|
||||
{
|
||||
throw new ServiceException("标的数据未找到:" + underlyingCode1);
|
||||
}
|
||||
|
||||
// 篮子标的到期日
|
||||
DateTime? MaturityDate = DateTime.MaxValue;
|
||||
foreach (var item in model.Items)
|
||||
{
|
||||
DateTime? Date = DataCacheProvider.GetUnderlyingDataSource().GetData(item.code).MaturityDate;
|
||||
MaturityDate = Date < MaturityDate ? Date : MaturityDate;
|
||||
item.Price = null;
|
||||
}
|
||||
|
||||
//----------------------------------
|
||||
// 新增variety 如果没有该品种 则新增
|
||||
//-------------
|
||||
if (variety.id == 0)
|
||||
{
|
||||
variety = new Variety()
|
||||
{
|
||||
VarietyCode = "篮子标的",
|
||||
VarietyName = "篮子标的",
|
||||
OptId = model.OptId,
|
||||
OptName = model.OptName,
|
||||
OptDate = model.OptDate,
|
||||
TradingMarketId = 0,
|
||||
TradeUnit = "100股/手",
|
||||
QuoteUnit = "元(人民币)/股",
|
||||
DeliveryType = "",
|
||||
HasNightMarket = false,
|
||||
ShortName = "篮子标的",
|
||||
CommissionType = "固定",
|
||||
CloseTodayCommissionType = "固定",
|
||||
//UnderlyingInstrumentType = "Stock",
|
||||
VolatilityRate = "",
|
||||
VolatilityAdjust = 0
|
||||
};
|
||||
DbContext.variety.Add(variety);
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
underlying_manager underlying;
|
||||
|
||||
if (isAddNew)
|
||||
{
|
||||
underlying = new underlying_manager
|
||||
{
|
||||
UnderlyingCode = model.UnderlyingCode,
|
||||
UnderlyingType = variety.VarietyName,
|
||||
UnderlyingTypeId = variety.id,
|
||||
UnderlyingName = model.UnderlyingCode,
|
||||
CommodityCode = variety.VarietyCode,
|
||||
OpenDate = DateTime.Today
|
||||
};
|
||||
DbContext.underlying_manager.Add(underlying);
|
||||
}
|
||||
else
|
||||
{
|
||||
underlying = DbContext.underlying_manager.FirstOrDefault(u => u.UnderlyingCode == model.UnderlyingCode);
|
||||
if (underlying == null)
|
||||
{
|
||||
throw new ServiceException("数据不存在:" + model.UnderlyingCode);
|
||||
}
|
||||
underlying.LaunchState = "1";
|
||||
underlying.LastUpdateTime = OptDate;
|
||||
}
|
||||
|
||||
underlying.SubData = JsonHelper.Stringify(model.Items);
|
||||
|
||||
underlying.OptId = UserId;
|
||||
underlying.OptName = UserName;
|
||||
underlying.OptDate = OptDate;
|
||||
|
||||
underlying.Price = 0;
|
||||
|
||||
underlying.MaturityDate = MaturityDate == DateTime.MaxValue ? null : MaturityDate;
|
||||
underlying.UnderlyingState = "Live";
|
||||
underlying.UnderlyingStatus = "正常运行";
|
||||
|
||||
underlying.MarketCode = underlying1.MarketCode;
|
||||
underlying.UnderlyingInstrumentType = underlying1.UnderlyingInstrumentType;
|
||||
|
||||
//----------------------------------
|
||||
//2020/5/14 使用组合标的的第一个标的为新添加的字段赋值
|
||||
//----------------------------------
|
||||
underlying.TradeUnit = underlying1.TradeUnit;
|
||||
underlying.QuoteUnit = underlying1.QuoteUnit;
|
||||
underlying.MarketName = underlying1.MarketName;
|
||||
|
||||
if (string.IsNullOrEmpty(underlying.TradeUnit))
|
||||
{
|
||||
underlying.TradeUnit = "份";
|
||||
}
|
||||
|
||||
DbContext.SaveChanges();
|
||||
//----------------------------------
|
||||
// 新增underlying_parameter
|
||||
//----------------------------------
|
||||
|
||||
var underlyingParams = DbContext.underlying_parameter.Where(u => u.UnderlyingId == underlying.id).ToList();
|
||||
|
||||
//如果没有报价参数,则新增
|
||||
if (underlyingParams.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 = model.OptId,
|
||||
OptName = model.OptName
|
||||
};
|
||||
DbContext.underlying_parameter.Add(up);
|
||||
underlyingParams.Add(up);
|
||||
});
|
||||
}
|
||||
|
||||
//最后调用保存以保证事物完整性
|
||||
return DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 篮子标的查看
|
||||
/// </summary>
|
||||
public BasketUnderlyingDto GetBasketUnderlyingByName(string name)
|
||||
{
|
||||
|
||||
var query = from u in DbContext.underlying_manager.AsEnumerable()
|
||||
where u.UnderlyingCode == name
|
||||
select new BasketUnderlyingDto
|
||||
{
|
||||
Items = JsonConvert.DeserializeObject<List<BasketUnderlyingItem>>(u.SubData),
|
||||
};
|
||||
|
||||
var res = query.FirstOrDefault();
|
||||
|
||||
double price = 0;
|
||||
|
||||
foreach (var item in res.Items)
|
||||
{
|
||||
DataCacheProvider.GetUnderlyingDataSource().TryGetPrice(item.code, out price);
|
||||
item.Price = price;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class BasketUnderlyingDto : UnderlyingManagerDto
|
||||
{
|
||||
/// <summary>
|
||||
/// 篮子标的项目
|
||||
/// </summary>
|
||||
public IEnumerable<BasketUnderlyingItem> Items { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 篮子标的合成项
|
||||
/// </summary>
|
||||
public class BasketUnderlyingItem
|
||||
{
|
||||
public double? Price { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权重
|
||||
/// </summary>
|
||||
public double weight { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 份额
|
||||
/// </summary>
|
||||
public double notional { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标的代码
|
||||
/// </summary>
|
||||
public string code { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
using System.Data;
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 场内期权数据服务
|
||||
/// </summary>
|
||||
public class ExchangeOptionDataService : YLBaseService
|
||||
{
|
||||
public ExchangeOptionDataService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public ExchangeOptionDataService(YLBaseService baseService) : base(baseService)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询exchange_list_option
|
||||
/// </summary>
|
||||
public IPagedList<ExchangeListOption> SearchList(ExchangeOptionReq req)
|
||||
{
|
||||
var predicate = PredicateBuilder.True<ExchangeListOption>();
|
||||
|
||||
if (!string.IsNullOrEmpty(req.ContractCode))
|
||||
{
|
||||
predicate = predicate.And(d => d.ContractCode.Contains(req.ContractCode));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.UnderlyingCode))
|
||||
{
|
||||
predicate = predicate.And(d => d.UnderlyingCode.Contains(req.UnderlyingCode));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.OptionType))
|
||||
{
|
||||
predicate = predicate.And(d => d.OptionType.Contains(req.OptionType));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.ExerciseMode))
|
||||
{
|
||||
predicate = predicate.And(d => d.ExerciseMode.Contains(req.ExerciseMode));
|
||||
}
|
||||
|
||||
if (req.MaturityDateStart != DateTime.MinValue)
|
||||
{
|
||||
predicate = predicate.And(d => d.MaturityDate >= req.MaturityDateStart);
|
||||
}
|
||||
|
||||
if (req.MaturityDateEnd != DateTime.MinValue)
|
||||
{
|
||||
predicate = predicate.And(d => d.MaturityDate <= req.MaturityDateEnd);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.MarketCode))
|
||||
{
|
||||
predicate = predicate.And(d => d.MarketCode == req.MarketCode);
|
||||
}
|
||||
|
||||
var query = DbContext.exchange_list_option.Where(predicate);
|
||||
|
||||
return query.ToPagedList(req);
|
||||
}
|
||||
|
||||
public IEnumerable<ExchangeListOption> GetSelectItems(string underlyingCode)
|
||||
{
|
||||
return DbContext.exchange_list_option.Where(n => n.UnderlyingCode == underlyingCode).OrderByDescending(n => n.id).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public class ExchangeOptionReq : PagedQueryModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 合约代码
|
||||
/// </summary>
|
||||
public string ContractCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标的代码
|
||||
/// </summary>
|
||||
public string UnderlyingCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 看涨看跌
|
||||
/// </summary>
|
||||
public string OptionType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 行权方式
|
||||
/// </summary>
|
||||
public string ExerciseMode { get; set; }
|
||||
|
||||
public DateTime MaturityDateStart { get; set; }
|
||||
|
||||
public DateTime MaturityDateEnd { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 市场代码
|
||||
/// </summary>
|
||||
public string MarketCode { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,447 @@
|
||||
using BaseOUDAL;
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using YLErp.Commons;
|
||||
using YLErp.Configuration.Enums;
|
||||
using YLErp.Helpers;
|
||||
using YLErp.Model;
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 个股黑白名单信息管理服务
|
||||
/// </summary>
|
||||
public class StockBlackWhiteService : YLBaseService
|
||||
{
|
||||
public StockBlackWhiteService(YLBaseService baseService) : base(baseService)
|
||||
{
|
||||
}
|
||||
|
||||
public StockBlackWhiteService(OptUserInfo userInfo) :
|
||||
base(userInfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
private string getUnderlyingType(string code)
|
||||
{
|
||||
string assetVariety = "";
|
||||
if (code.StartsWith("60") || code.StartsWith("000"))
|
||||
{ //主板
|
||||
assetVariety = "ZB";
|
||||
}
|
||||
else if (code.StartsWith("002"))
|
||||
{//中小板
|
||||
assetVariety = "ZXB";
|
||||
}
|
||||
else if (code.StartsWith("300"))
|
||||
{//创业板
|
||||
assetVariety = "CYB";
|
||||
}
|
||||
else if (code.StartsWith("688"))
|
||||
{//科创版
|
||||
assetVariety = "KCB";
|
||||
}
|
||||
else
|
||||
{
|
||||
assetVariety = "JW";
|
||||
}
|
||||
return assetVariety;
|
||||
}
|
||||
public void StockBlackWhiteAddJson(List<StockBlackWhite> data, bool checkStatus)
|
||||
{
|
||||
if (data.Any(O => string.IsNullOrWhiteSpace(O.UnderlyingCode)))
|
||||
{
|
||||
throw new ServiceException("代码不应为空");
|
||||
}
|
||||
var query = data.Where(O => !O.UnderlyingCode.Contains("."));
|
||||
if (query.Any())
|
||||
{
|
||||
var errCode = query.Select(O => O.UnderlyingCode);
|
||||
throw new ServiceException($"{string.Join(",", errCode)}代码应包含市场后缀");
|
||||
}
|
||||
query = data.Where(O => O.BlackWhiteState < 0 || O.BlackWhiteState > 1);
|
||||
if (query.Any())
|
||||
{
|
||||
var errCode = query.Select(O => O.UnderlyingCode);
|
||||
throw new ServiceException($"{string.Join(",", errCode)}记录应指定所属黑名单或白名单");
|
||||
}
|
||||
for (int i = 0; i < data.Count; i++)
|
||||
{
|
||||
data[i].UnderlyingCode = data[i].UnderlyingCode.ToUpper();
|
||||
if (data[i].LimitRange == LimitRangeEnum.All)
|
||||
{
|
||||
data[i].LimitRange = LimitRangeEnum.Option;
|
||||
data.Add(new StockBlackWhite()
|
||||
{
|
||||
UnderlyingCode = data[i].UnderlyingCode,
|
||||
UnderlyingName = data[i].UnderlyingName,
|
||||
BlackWhiteState = data[i].BlackWhiteState,
|
||||
LimitRange = LimitRangeEnum.Swap
|
||||
});
|
||||
}
|
||||
}
|
||||
if (checkStatus)
|
||||
{
|
||||
var newCodeDict = data.GroupBy(O => O.BlackWhiteState).ToDictionary(K => K.Key, V => V.Select(O => O));
|
||||
var predicate = PredicateBuilder.False<StockBlackWhite>();
|
||||
if (newCodeDict.ContainsKey(0))
|
||||
{
|
||||
var blackList = newCodeDict[0].Select(O => O.UnderlyingCode).ToHashSet();
|
||||
var limits = newCodeDict[0].Select(O => O.LimitRange).ToHashSet();
|
||||
predicate = predicate.Or(O => O.BlackWhiteState != 0 && limits.Contains(O.LimitRange) && blackList.Contains(O.UnderlyingCode));
|
||||
}
|
||||
if (newCodeDict.ContainsKey(1))
|
||||
{
|
||||
var whiteList = newCodeDict[1].Select(O => O.UnderlyingCode).ToHashSet();
|
||||
var limits = newCodeDict[1].Select(O => O.LimitRange).ToHashSet();
|
||||
predicate = predicate.Or(O => O.BlackWhiteState != 1 && limits.Contains(O.LimitRange) && whiteList.Contains(O.UnderlyingCode));
|
||||
}
|
||||
var checkData =
|
||||
DbContext.Stock_BlackWhite.Where(predicate)
|
||||
.AsEnumerable()
|
||||
.GroupBy(O => O.BlackWhiteState).ToDictionary(K => K.Key, V => V.Select(O => O.UnderlyingCode));
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (checkData.Count > 0)
|
||||
{
|
||||
if (checkData.ContainsKey(0))
|
||||
{
|
||||
sb.Append($"{string.Join(",", checkData[0])}代码存在于黑名单中,");
|
||||
}
|
||||
if (checkData.ContainsKey(1))
|
||||
{
|
||||
sb.Append($"{string.Join(",", checkData[1])}代码存在于白名单中,");
|
||||
}
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
sb.Append("是否覆盖?");
|
||||
}
|
||||
}
|
||||
if (sb.Length > 0)
|
||||
{
|
||||
throw new ServiceException(sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
var codes = data.Select(O => O.UnderlyingCode);
|
||||
var codeDict = DbContext.underlying_manager.Where(O => O.UnderlyingInstrumentType == "Stock" && codes.Contains(O.UnderlyingCode)).ToDictionary(K => K.UnderlyingCode, V => V);
|
||||
|
||||
var dbDict = DbContext.Stock_BlackWhite.AsEnumerable().GroupBy(O => O.UnderlyingCode).ToDictionary(K => K.Key, V => V.ToArray());
|
||||
var tempList = new HashSet<string>();
|
||||
foreach (var item in data)
|
||||
{
|
||||
if (!codeDict.ContainsKey(item.UnderlyingCode))
|
||||
{
|
||||
if (item.BlackWhiteState != 0)
|
||||
{
|
||||
item.UnderlyingCode = item.UnderlyingCode.ToUpper();
|
||||
//如果标的不存在,则自动创建;如果标的资产类型不在已知范围内,则创建失败;
|
||||
var varietyCode = getUnderlyingType(item.UnderlyingCode);
|
||||
var marketCode = item.UnderlyingCode.Split('.')[1];
|
||||
var tempName = $"A股股票{(marketCode == "SZ" ? "深圳" : "上海")}";
|
||||
var variety =
|
||||
DataCacheProvider.GetVarietyDataSource().AsQueryable().Where(O => O.VarietyCode == varietyCode).FirstOrDefault()
|
||||
?? DataCacheProvider.GetVarietyDataSource().AsQueryable().Where(O => O.VarietyName == tempName).FirstOrDefault();
|
||||
|
||||
var um = new underlying_manager();
|
||||
um.UnderlyingCode = item.UnderlyingCode;
|
||||
um.UnderlyingName = item.UnderlyingName;
|
||||
um.UnderlyingInstrumentType = "Stock";
|
||||
um.UnderlyingType = variety?.VarietyCode;
|
||||
um.UnderlyingTypeId = variety?.id ?? 0;
|
||||
um.LaunchState = item.BlackWhiteState.ToString();
|
||||
um.MarketCode = marketCode;
|
||||
um.UnderlyingState = "Live";
|
||||
um.UnderlyingStatus = "正常运行";
|
||||
um.TradeCode = item.UnderlyingCode;
|
||||
um.UnderlyingDesc = "黑白名单同步";
|
||||
var underlyingService = new UnderlyingDalService(OptUser).SaveUnderlyingData(um);
|
||||
codeDict[item.UnderlyingCode] = um;
|
||||
}
|
||||
}
|
||||
if (!tempList.Add($"{item.UnderlyingCode}_{item.LimitRange}"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
StockBlackWhite stockBlackWhite =
|
||||
dbDict.ContainsKey(item.UnderlyingCode) ? dbDict[item.UnderlyingCode].FirstOrDefault(c =>
|
||||
c.UnderlyingCode == item.UnderlyingCode &&
|
||||
(c.LimitRange == LimitRangeEnum.All ||
|
||||
c.LimitRange == item.LimitRange)) : null;
|
||||
|
||||
if (stockBlackWhite == null)
|
||||
{
|
||||
stockBlackWhite = new StockBlackWhite
|
||||
{
|
||||
UnderlyingCode = item.UnderlyingCode,
|
||||
};
|
||||
DbContext.Stock_BlackWhite.Add(stockBlackWhite);
|
||||
}
|
||||
stockBlackWhite.UnderlyingName = codeDict.ContainsKey(item.UnderlyingCode) ? codeDict[item.UnderlyingCode].UnderlyingName : item.UnderlyingName ?? "";
|
||||
stockBlackWhite.BlackWhiteState = item.BlackWhiteState;
|
||||
stockBlackWhite.LimitRange = item.LimitRange;
|
||||
stockBlackWhite.OptId = UserId;
|
||||
stockBlackWhite.OptName = UserName;
|
||||
stockBlackWhite.OptDate = DateTime.Now;
|
||||
}
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
/// <summary>
|
||||
/// 查询股票黑白名单列表
|
||||
/// </summary>
|
||||
/// <param name="req"></param>
|
||||
/// <returns></returns>
|
||||
public SearchListResult<StockBlackWhite> SearchList(StockBlackWhiteQuery req, bool needSign = false)
|
||||
{
|
||||
var query = from source in DbContext.Stock_BlackWhite select source;
|
||||
if (!string.IsNullOrEmpty(req.UnderlyingCode))
|
||||
{
|
||||
query = query.Where(d => d.UnderlyingCode.Contains(req.UnderlyingCode));
|
||||
}
|
||||
if (!string.IsNullOrEmpty(req.UnderlyingName))
|
||||
{
|
||||
query = query.Where(d => d.UnderlyingName.Contains(req.UnderlyingName));
|
||||
}
|
||||
//if (req.tabIndex == (int)StockBlackWhiteEnum.黑名单)
|
||||
//{
|
||||
// query = query.Where(d => d.BlackWhiteState == 0);
|
||||
//}
|
||||
//if (req.tabIndex == (int)StockBlackWhiteEnum.白名单)
|
||||
//{
|
||||
// query = query.Where(d => d.BlackWhiteState == 1);
|
||||
//}
|
||||
if (req.OptId != null)
|
||||
{
|
||||
query = query.Where(d => d.OptId == req.OptId);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.OptName))
|
||||
{
|
||||
query = query.Where(d => d.OptName.Contains(req.OptName));
|
||||
}
|
||||
if (req.BlackWhiteState >= 0)
|
||||
{
|
||||
query = query.Where(d => d.BlackWhiteState == req.BlackWhiteState);
|
||||
}
|
||||
if (req.LimitRange != LimitRangeEnum.All)
|
||||
{
|
||||
query = query.Where(O => O.LimitRange == LimitRangeEnum.All || O.LimitRange == req.LimitRange);
|
||||
}
|
||||
if (string.IsNullOrEmpty(req.sidx))
|
||||
{
|
||||
req.sidx = "id";
|
||||
req.sord = "asc";
|
||||
}
|
||||
SearchListResult<StockBlackWhite> retListResult = query.ToSearchList(req);
|
||||
if (needSign)
|
||||
{
|
||||
var list = retListResult.rows.Select(O => O.UnderlyingCode);
|
||||
if (list.Count() > 0)
|
||||
{
|
||||
var codes = DbContext.Stock_BlackWhite
|
||||
.Where(O => O.LimitRange == req.LimitRange && O.BlackWhiteState != req.BlackWhiteState && list.Contains(O.UnderlyingCode))
|
||||
.Select(O => O.UnderlyingCode);
|
||||
foreach (var item in retListResult.rows)
|
||||
{
|
||||
item.NeedSign = codes.Contains(item.UnderlyingCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retListResult;
|
||||
}
|
||||
public bool ImportStockBlackWhitePublic(Stream stream, int blackWhiteState, bool checkStatus)
|
||||
{
|
||||
try
|
||||
{
|
||||
List<ExcelHelper.DataColumnModel> dc = new List<ExcelHelper.DataColumnModel>();
|
||||
dc.Add(new ExcelHelper.DataColumnModel("标的资产代码", nameof(StockBlackWhite.UnderlyingCode), (cv, obj) =>
|
||||
{
|
||||
return ((string)cv ?? "").ToUpper();
|
||||
}));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("标的名称", nameof(StockBlackWhite.UnderlyingName)));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("名单类别", nameof(StockBlackWhite.BlackWhiteState), (cv, obj) =>
|
||||
{
|
||||
int result = -1;
|
||||
switch (cv)
|
||||
{
|
||||
case "黑名单":
|
||||
result = 0;
|
||||
break;
|
||||
case "白名单":
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("业务类别", nameof(StockBlackWhite.LimitRange), (cv, obj) =>
|
||||
{
|
||||
LimitRangeEnum result = ((string)cv).GetEnumByDescription<LimitRangeEnum>();
|
||||
return result;
|
||||
}));
|
||||
var dict = new ExcelHelper().ExcelToListT<StockBlackWhite>(dc.ToArray(), stream, new[] { "场外期权", "互换" });
|
||||
var stockBlackWhite = new List<StockBlackWhite>();
|
||||
foreach (var item in dict)
|
||||
{
|
||||
foreach (var O in item.Value)
|
||||
{
|
||||
O.LimitRange = item.Key == "场外期权" ? LimitRangeEnum.Option : LimitRangeEnum.Swap;
|
||||
O.BlackWhiteState = blackWhiteState;
|
||||
O.OptId = UserId;
|
||||
O.OptName = UserName;
|
||||
O.OptDate = DateTime.Now;
|
||||
}
|
||||
stockBlackWhite.AddRange(item.Value);
|
||||
}
|
||||
|
||||
StockBlackWhiteAddJson(stockBlackWhite, checkStatus);
|
||||
return true;
|
||||
}
|
||||
catch (ServiceException) { throw; }
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger("StockBlackWhiteStarvice").Error(ex, "导入黑白名单数据,操作出错");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
public bool DeleteStockBlackWhite(IEnumerable<int> ids, LimitRangeEnum limitRange, int blackWhiteState)
|
||||
{
|
||||
var targetLimit = limitRange == LimitRangeEnum.Option ? LimitRangeEnum.Swap : LimitRangeEnum.Option;
|
||||
List<StockBlackWhite> delList = new List<StockBlackWhite>();
|
||||
var query = DbContext.Stock_BlackWhite.Where(O => ids.Contains(O.id) && O.BlackWhiteState == blackWhiteState);
|
||||
var data = query.Where(c => c.LimitRange == limitRange);
|
||||
DbContext.Stock_BlackWhite.RemoveRange(data);
|
||||
data = query.Where(O => O.LimitRange == LimitRangeEnum.All);
|
||||
foreach (var item in data)
|
||||
{
|
||||
item.LimitRange = targetLimit;
|
||||
item.OptId = UserId;
|
||||
item.OptName = UserName;
|
||||
item.OptDate = DateTime.Now;
|
||||
}
|
||||
DbContext.SaveChanges();
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取标的黑白名单列表
|
||||
/// </summary>
|
||||
/// <param name="limitRange">获取黑白名单的维度</param>
|
||||
/// <param name="Codes">黑白名单都不存在时,该值为Null,只存在黑名单时返回黑名单列表,否则返回包含在白名单且不包含在黑名单中的列表</param>
|
||||
/// <returns>黑白名单都不存在或黑白名单都存在或只存在白名单时,返回false;只存在黑名单时,返回true;</returns>
|
||||
public bool GetStockBlackWhiteList(LimitRangeEnum limitRange, out List<string> Codes)
|
||||
{
|
||||
var useWhiteCode = false;
|
||||
System.Diagnostics.Debug.WriteLine($"{"".PadLeft(50, '=')}");
|
||||
var blackWhiteQuery = DataCacheProvider.GetStockBlackWhiteDataSource().AsQueryable()
|
||||
.Where(O => O.LimitRange == Configuration.Enums.LimitRangeEnum.All || O.LimitRange == limitRange);
|
||||
var existBlackLimit = blackWhiteQuery.Any(O => O.BlackWhiteState == 0);
|
||||
var existWhiteLimit = blackWhiteQuery.Any(O => O.BlackWhiteState == 1);
|
||||
if (existBlackLimit || existWhiteLimit)//如果黑白名单都不存在,则不限制;
|
||||
{
|
||||
var blackCodes = new List<string>();
|
||||
var whiteCodes = new List<string>();
|
||||
if (existBlackLimit)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"存在黑名单");
|
||||
blackCodes = blackWhiteQuery
|
||||
.Where(O => O.BlackWhiteState == 0)
|
||||
.Select(O => O.UnderlyingCode).ToList();
|
||||
}
|
||||
if (existWhiteLimit)
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"存在白名单");
|
||||
useWhiteCode = false;
|
||||
whiteCodes = blackWhiteQuery
|
||||
.Where(O => O.BlackWhiteState == 1 && !blackCodes.Contains(O.UnderlyingCode))
|
||||
.Select(O => O.UnderlyingCode).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
System.Diagnostics.Debug.WriteLine($"不存在白名单");
|
||||
useWhiteCode = true;
|
||||
whiteCodes.AddRange(blackCodes);
|
||||
blackCodes.Clear();
|
||||
}
|
||||
whiteCodes.RemoveAll(O => blackCodes.Contains(O));
|
||||
Codes = new List<string>(whiteCodes.ToHashSet());
|
||||
}
|
||||
else
|
||||
{
|
||||
Codes = null;
|
||||
}
|
||||
|
||||
return useWhiteCode;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 2021-05-21:天风证券已经修改了逻辑,股票启用与否和黑白名单断开了关系
|
||||
/// 这段代码也没有经过测试,暂时先留着,如果没用,3.14版本就删除掉
|
||||
/// </summary>
|
||||
public string CanSetLaunchState(int[] uids, string launchState)
|
||||
{
|
||||
if (uids == null || uids.Any(n => n > 0))
|
||||
{
|
||||
return "请求参数为空";
|
||||
}
|
||||
|
||||
//如果禁用标的则检查是否有交易正在使用要禁用的标的
|
||||
if (launchState != "1")
|
||||
{
|
||||
var query1 = from a in DbContext.underlying_manager
|
||||
join t in DbContext.trade on a.UnderlyingCode equals t.UnderlyingCode
|
||||
where uids.Contains(a.id)
|
||||
&& !ConsTrade.TradeCompleteStatus.Contains(t.TradeStatus) && t.ValidState != ConsGlobal.InValid
|
||||
select t.UnderlyingCode;
|
||||
|
||||
var arr = query1.ToArray();
|
||||
|
||||
if (arr.Length > 0)
|
||||
{
|
||||
var codeStr = string.Join(",", arr);
|
||||
|
||||
return $"不能禁用标的,有{arr.Length }笔交易还在使用标的:{codeStr}";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
var query = from a in DbContext.underlying_manager
|
||||
join b in DbContext.Stock_BlackWhite on a.UnderlyingCode equals b.UnderlyingCode into bs
|
||||
from b in bs.DefaultIfEmpty()
|
||||
where uids.Contains(a.id) && a.UnderlyingInstrumentType == ConsGlobal.InstrumentType.Stock
|
||||
select new
|
||||
{
|
||||
a.UnderlyingCode,
|
||||
state = b == null ? 100 : b.BlackWhiteState
|
||||
};
|
||||
|
||||
var datas = query.ToArray();
|
||||
|
||||
if (!datas.Any())
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (datas.Any(n => n.state == 1) || DbContext.Stock_BlackWhite.Any(n => n.BlackWhiteState == 1))
|
||||
{
|
||||
if (!datas.All(n => n.state == 1))
|
||||
{
|
||||
var codeStr = string.Join(",", datas.Where(n => n.state != 1).Select(n => n.UnderlyingCode).ToArray());
|
||||
|
||||
return "禁止不在白名单中的标的启用:" + codeStr;
|
||||
}
|
||||
}
|
||||
|
||||
if (datas.Any(n => n.state == 0))
|
||||
{
|
||||
var codeStr = string.Join(",", datas.Where(n => n.state == 0).Select(n => n.UnderlyingCode).ToArray());
|
||||
|
||||
return "禁止在黑名单中的标的启用:" + codeStr;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
using System.Data;
|
||||
using YLErp.Commons;
|
||||
using YLErp.Core.DBModels;
|
||||
using YLErp.Model;
|
||||
using YLErp.Modules;
|
||||
|
||||
namespace YLErp.BLL
|
||||
{
|
||||
public class SuperviseUndelryingBLL : YLBaseService
|
||||
{
|
||||
public SuperviseUndelryingBLL(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
|
||||
private readonly YLContext db = new YLContext();
|
||||
|
||||
/// <summary>
|
||||
/// 查询所有报送标的代码
|
||||
/// </summary>
|
||||
/// <param name="req"></param>
|
||||
/// <returns></returns>
|
||||
public List<supervise_undelrying> GetAll(Supervise_UndelryingReq req)
|
||||
{
|
||||
|
||||
var undelrying = req.undelrying.TrimToNull();
|
||||
var query = (from source in db.supervise_undelrying
|
||||
|
||||
where undelrying == null || source.undelrying.Contains(undelrying)
|
||||
select source).AsQueryable().ToList();
|
||||
return query;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量删除监管报送参数
|
||||
/// </summary>
|
||||
public void DeleteSuperviseUndelryings(IEnumerable<int> superviseUndelryingIds)
|
||||
{
|
||||
var superviseUndelryingIdList = superviseUndelryingIds.ToList();
|
||||
var superviseUndelryingList = DbContext.supervise_undelrying.Where(O => superviseUndelryingIdList.Contains(O.id)).ToList();
|
||||
DbContext.supervise_undelrying.RemoveRange(superviseUndelryingList);
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// excel导入监管报送参数
|
||||
/// </summary>
|
||||
/// <param name="streamIn"></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="ServiceException"></exception>
|
||||
public ImportResultModel superviseUndelryingImportFromExcel(Stream streamIn)
|
||||
{
|
||||
var importModels = Enumerable.Empty<ImportModel>();
|
||||
var rowIndex = 0;
|
||||
|
||||
try
|
||||
{
|
||||
var ds = Office.ExcelHelper.ReadExcelAsDataSet(streamIn);
|
||||
|
||||
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 ul = reader.GetString("代码", false);
|
||||
//代码为空时,跳过这条数据
|
||||
if (string.IsNullOrEmpty(ul))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var ul_cfmmc = reader.GetString("报送代码CFMMC", false);
|
||||
var model = list.FirstOrDefault(n => n.undelrying == ul);
|
||||
if (model == null)
|
||||
{
|
||||
model = new ImportModel
|
||||
{
|
||||
undelrying = ul,
|
||||
undelrying_CFMMC = ul_cfmmc,
|
||||
};
|
||||
list.Add(model);
|
||||
}
|
||||
else
|
||||
{
|
||||
model.undelrying = ul;
|
||||
model.undelrying_CFMMC = ul_cfmmc;
|
||||
}
|
||||
|
||||
}
|
||||
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()
|
||||
};
|
||||
|
||||
|
||||
foreach (var item in importModels)
|
||||
{
|
||||
var underlying = item.undelrying;
|
||||
|
||||
var superviseUndelrying = DbContext.supervise_undelrying.FirstOrDefault(n => n.undelrying == underlying);
|
||||
|
||||
if (superviseUndelrying == null)
|
||||
{
|
||||
DbContext.supervise_undelrying.Add(new supervise_undelrying
|
||||
{
|
||||
undelrying = item.undelrying,
|
||||
undelrying_CFMMC = item.undelrying_CFMMC,
|
||||
CreateTime = DateTime.Now
|
||||
});
|
||||
result.SuccessCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
superviseUndelrying.undelrying_CFMMC = item.undelrying_CFMMC;
|
||||
result.SuccessCount++;
|
||||
}
|
||||
}
|
||||
DbContext.SaveChanges();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
class ImportModel
|
||||
{
|
||||
public string undelrying { get; set; }
|
||||
|
||||
public string undelrying_CFMMC { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
namespace YLErp.BLL
|
||||
{
|
||||
public class synthetic_underlyingBLL
|
||||
{
|
||||
public static IQueryable<SyntheticUnderlying> GetQuery()
|
||||
{
|
||||
return new YLContext().synthetic_underlying.AsNoTracking();
|
||||
}
|
||||
|
||||
public static SyntheticUnderlying GetByName(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name)) return null;
|
||||
|
||||
using (var db = new YLContext())
|
||||
{
|
||||
return db.synthetic_underlying.AsNoTracking().FirstOrDefault(n => n.Name == name);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetUnderlyingTipsInfo(string name)
|
||||
{
|
||||
if (string.IsNullOrEmpty(name)) return null;
|
||||
|
||||
using (var db = new YLContext())
|
||||
{
|
||||
return db.synthetic_underlying.AsNoTracking().FirstOrDefault(n => n.Name == name)?.UnderlyingTipsInfo;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static List<SyntheticUnderlying> GetListByNames(List<string> names)
|
||||
{
|
||||
using (var db = new YLContext())
|
||||
{
|
||||
return db.synthetic_underlying.AsNoTracking().Where(n => names.Contains(n.Name)).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,265 @@
|
||||
using YLErp.BLL;
|
||||
using YLErp.Commons;
|
||||
using YLErp.QdpModule;
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 合成价差期权价格服务
|
||||
/// </summary>
|
||||
public class SyntheticUnderlyingPriceService : YLBaseService
|
||||
{
|
||||
public SyntheticUnderlyingPriceService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取合成价差期权价格
|
||||
/// </summary>
|
||||
public double? GetPrice(string underlyingCode)
|
||||
{
|
||||
if (string.IsNullOrEmpty(underlyingCode))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var query = from su in DbContext.synthetic_underlying
|
||||
join u in DbContext.underlying_manager on su.Name equals u.UnderlyingCode
|
||||
join u1 in DbContext.underlying_manager on su.UnderlyingCode1 equals u1.UnderlyingCode into u1t
|
||||
from u1 in u1t.DefaultIfEmpty()
|
||||
join u2 in DbContext.underlying_manager on su.UnderlyingCode2 equals u2.UnderlyingCode into u2t
|
||||
from u2 in u2t.DefaultIfEmpty()
|
||||
join u3 in DbContext.underlying_manager on su.UnderlyingCode3 equals u3.UnderlyingCode into u3t
|
||||
from u3 in u3t.DefaultIfEmpty()
|
||||
join u4 in DbContext.underlying_manager on su.UnderlyingCode4 equals u4.UnderlyingCode into u4t
|
||||
from u4 in u4t.DefaultIfEmpty()
|
||||
where u.UnderlyingCode == underlyingCode
|
||||
select new
|
||||
{
|
||||
Price = (u1.Price ?? 0) * (su.Coefficient1 ?? 0)
|
||||
+ (u2.Price ?? 0) * (su.Coefficient2 ?? 0)
|
||||
+ (u3.Price ?? 0) * (su.Coefficient3 ?? 0)
|
||||
+ (u4.Price ?? 0) * (su.Coefficient4 ?? 0)
|
||||
+ (su.Constant ?? 0)
|
||||
};
|
||||
|
||||
return query.FirstOrDefault()?.Price;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取合成价差期权价格
|
||||
/// </summary>
|
||||
public SyntheticPriceModel GetPriceModel(string underlyingCode)
|
||||
{
|
||||
if (string.IsNullOrEmpty(underlyingCode))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var query = from su in DbContext.synthetic_underlying
|
||||
join u in DbContext.underlying_manager on su.Name equals u.UnderlyingCode
|
||||
join u1 in DbContext.underlying_manager on su.UnderlyingCode1 equals u1.UnderlyingCode into u1t
|
||||
from u1 in u1t.DefaultIfEmpty()
|
||||
join u2 in DbContext.underlying_manager on su.UnderlyingCode2 equals u2.UnderlyingCode into u2t
|
||||
from u2 in u2t.DefaultIfEmpty()
|
||||
join u3 in DbContext.underlying_manager on su.UnderlyingCode3 equals u3.UnderlyingCode into u3t
|
||||
from u3 in u3t.DefaultIfEmpty()
|
||||
join u4 in DbContext.underlying_manager on su.UnderlyingCode4 equals u4.UnderlyingCode into u4t
|
||||
from u4 in u4t.DefaultIfEmpty()
|
||||
where u.UnderlyingCode == underlyingCode
|
||||
select new
|
||||
{
|
||||
su.Constant,
|
||||
su1 = u1 == null ? null : new UnderlyingPriceModel
|
||||
{
|
||||
UnderlyingCode = u1.UnderlyingCode,
|
||||
Price = u1.Price ?? 0,
|
||||
Coefficient = su.Coefficient1 ?? 0,
|
||||
ContractSize=su.ContractSize,
|
||||
},
|
||||
su2 = u2 == null ? null : new UnderlyingPriceModel
|
||||
{
|
||||
UnderlyingCode = u2.UnderlyingCode,
|
||||
Price = u2.Price ?? 0,
|
||||
Coefficient = su.Coefficient2 ?? 0,
|
||||
ContractSize = su.ContractSize
|
||||
},
|
||||
su3 = u3 == null ? null : new UnderlyingPriceModel
|
||||
{
|
||||
UnderlyingCode = u3.UnderlyingCode,
|
||||
Price = u3.Price ?? 0,
|
||||
Coefficient = su.Coefficient3 ?? 0,
|
||||
ContractSize = su.ContractSize
|
||||
},
|
||||
su4 = u4 == null ? null : new UnderlyingPriceModel
|
||||
{
|
||||
UnderlyingCode = u4.UnderlyingCode,
|
||||
Price = u4.Price ?? 0,
|
||||
Coefficient = su.Coefficient4 ?? 0,
|
||||
ContractSize = su.ContractSize
|
||||
},
|
||||
};
|
||||
|
||||
var data = query.FirstOrDefault();
|
||||
|
||||
if (data == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var list = new[] { data.su1, data.su2, data.su3, data.su4 };
|
||||
|
||||
list = list.Where(n => n != null).ToArray();
|
||||
|
||||
var model = new SyntheticPriceModel
|
||||
{
|
||||
SuList = list,
|
||||
Constant = data.Constant ?? 0,
|
||||
Price = list.Sum(n => n.Price * n.Coefficient) + (data.Constant ?? 0)
|
||||
};
|
||||
|
||||
model.Price = OtcFormatHelper.FormatValue(model.Price, OtcFormatHelper.FormatModel.trading.umprice.precision);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public SyntheticPriceModel GetPriceModel(string underlyingCode,DateTime valueDate)
|
||||
{
|
||||
valueDate = valueDate.Date;
|
||||
|
||||
//传进来的可能是非交易日期
|
||||
valueDate = PS.Config.IsGuoJun ? QdpCalendarHelper.GetNonHolidayDefore(valueDate) : QdpCalendarHelper.GetNonHoliday(valueDate);
|
||||
var manager = DbContext.underlying_manager.FirstOrDefault(p => p.UnderlyingCode.Equals(underlyingCode));
|
||||
if (manager == null)
|
||||
{
|
||||
throw new ServiceException("未找到对应标的");
|
||||
}
|
||||
|
||||
valueDate = manager.UnderlyingInstrumentType != ConsGlobal.InstrumentType.CommodityFutures || manager.MaturityDate > valueDate ? valueDate : manager.MaturityDate.Value;
|
||||
|
||||
if (valueDate < valuedateBLL.ValueDate)
|
||||
{
|
||||
var syntheticUnderlying = DbContext.synthetic_underlying.FirstOrDefault(p => p.Name.Equals(underlyingCode));
|
||||
if (syntheticUnderlying == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var subUnderlyingCodes = new List<string>();
|
||||
if (!string.IsNullOrEmpty(syntheticUnderlying.UnderlyingCode1))
|
||||
{
|
||||
subUnderlyingCodes.Add(syntheticUnderlying.UnderlyingCode1);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(syntheticUnderlying.UnderlyingCode2))
|
||||
{
|
||||
subUnderlyingCodes.Add(syntheticUnderlying.UnderlyingCode2);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(syntheticUnderlying.UnderlyingCode3))
|
||||
{
|
||||
subUnderlyingCodes.Add(syntheticUnderlying.UnderlyingCode3);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(syntheticUnderlying.UnderlyingCode4))
|
||||
{
|
||||
subUnderlyingCodes.Add(syntheticUnderlying.UnderlyingCode4);
|
||||
}
|
||||
var subList=new List<UnderlyingPriceModel>();
|
||||
var futurePriceList = DbContext.eod_commodity_future_price.Where(p => p.ValueDate == valueDate && subUnderlyingCodes.Contains(p.UnderlyingCode)).ToList();
|
||||
if (futurePriceList != null && futurePriceList.Count > 0)
|
||||
{
|
||||
futurePriceList.ForEach(p =>
|
||||
{
|
||||
subList.Add(new UnderlyingPriceModel
|
||||
{
|
||||
UnderlyingCode = p.UnderlyingCode,
|
||||
Price = p.ClosePrice
|
||||
});
|
||||
|
||||
subUnderlyingCodes.Remove(subUnderlyingCodes.First(d=>d.Equals(p.UnderlyingCode,StringComparison.OrdinalIgnoreCase)));
|
||||
});
|
||||
}
|
||||
if (subUnderlyingCodes.Count > 0)
|
||||
{
|
||||
var stockPriceList = DbContext.eod_stock_price.Where(p => p.ValueDate == valueDate && subUnderlyingCodes.Contains(p.UnderlyingCode)).ToList();
|
||||
if (stockPriceList != null && stockPriceList.Count > 0)
|
||||
{
|
||||
stockPriceList.ForEach(p =>
|
||||
{
|
||||
subList.Add(new UnderlyingPriceModel
|
||||
{
|
||||
UnderlyingCode = p.UnderlyingCode,
|
||||
Price = p.ClosePrice
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
if (subList.Count == 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var resultSubList = new List<UnderlyingPriceModel>();
|
||||
SyntheticPriceModel result = new SyntheticPriceModel { SuList = resultSubList,Constant=syntheticUnderlying.Constant??0 };
|
||||
if (!string.IsNullOrEmpty(syntheticUnderlying.UnderlyingCode1))
|
||||
{
|
||||
var sub = subList.FirstOrDefault(d => d.UnderlyingCode.Equals(syntheticUnderlying.UnderlyingCode1,StringComparison.OrdinalIgnoreCase));
|
||||
if (sub != null)
|
||||
{
|
||||
sub.Coefficient = (double)syntheticUnderlying.Coefficient1;
|
||||
resultSubList.Add(sub);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultSubList.Add(new UnderlyingPriceModel { Coefficient = (double)syntheticUnderlying.Coefficient1, UnderlyingCode = syntheticUnderlying.UnderlyingCode1, Price = 0 });
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(syntheticUnderlying.UnderlyingCode2))
|
||||
{
|
||||
var sub = subList.FirstOrDefault(d => d.UnderlyingCode.Equals(syntheticUnderlying.UnderlyingCode2, StringComparison.OrdinalIgnoreCase));
|
||||
if (sub != null)
|
||||
{
|
||||
sub.Coefficient = (double)syntheticUnderlying.Coefficient2;
|
||||
resultSubList.Add(sub);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultSubList.Add(new UnderlyingPriceModel { Coefficient = (double)syntheticUnderlying.Coefficient2, UnderlyingCode = syntheticUnderlying.UnderlyingCode2, Price = 0 });
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(syntheticUnderlying.UnderlyingCode3))
|
||||
{
|
||||
var sub = subList.FirstOrDefault(d => d.UnderlyingCode.Equals(syntheticUnderlying.UnderlyingCode3, StringComparison.OrdinalIgnoreCase));
|
||||
if (sub != null)
|
||||
{
|
||||
sub.Coefficient = (double)syntheticUnderlying.Coefficient3;
|
||||
resultSubList.Add(sub);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultSubList.Add(new UnderlyingPriceModel { Coefficient = (double)syntheticUnderlying.Coefficient3, UnderlyingCode = syntheticUnderlying.UnderlyingCode3, Price = 0 });
|
||||
}
|
||||
}
|
||||
if (!string.IsNullOrEmpty(syntheticUnderlying.UnderlyingCode4))
|
||||
{
|
||||
var sub = subList.FirstOrDefault(d => d.UnderlyingCode.Equals(syntheticUnderlying.UnderlyingCode4, StringComparison.OrdinalIgnoreCase));
|
||||
if (sub != null)
|
||||
{
|
||||
sub.Coefficient = (double)syntheticUnderlying.Coefficient4;
|
||||
resultSubList.Add(sub);
|
||||
}
|
||||
else
|
||||
{
|
||||
resultSubList.Add(new UnderlyingPriceModel { Coefficient = (double)syntheticUnderlying.Coefficient4, UnderlyingCode = syntheticUnderlying.UnderlyingCode4, Price = 0 });
|
||||
}
|
||||
}
|
||||
result.Price= resultSubList.Sum(n => n.Price * n.Coefficient) + result.Constant;
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
return GetPriceModel(underlyingCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 板块性质服务
|
||||
/// </summary>
|
||||
public class UnderlyingBlockService : YLBaseService
|
||||
{
|
||||
public UnderlyingBlockService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有板块名称
|
||||
/// </summary>
|
||||
public IEnumerable<UnderlyingBlockConfig> GetBlocks(int? group)
|
||||
{
|
||||
var predicate = PredicateBuilder.Create<UnderlyingBlockConfig>(n => n.Group > 0);
|
||||
if (group.HasValue)
|
||||
{
|
||||
predicate = predicate.And(n => n.Group == group.Value);
|
||||
}
|
||||
return DbContext.UnderlyingBlockConfig.AsNoTracking()
|
||||
.Where(predicate).OrderByDescending(n => n.id).ToArray();
|
||||
}
|
||||
|
||||
public int SaveData(UnderlyingBlockConfig model)
|
||||
{
|
||||
UnderlyingBlockConfig dbModel;
|
||||
|
||||
if (model.id > 0)
|
||||
{
|
||||
dbModel = DbContext.UnderlyingBlockConfig.Find(model.id);
|
||||
if (DbContext.UnderlyingBlockConfig.Any(n => n.id != model.id && n.Group == dbModel.Group && n.Name == model.Name))
|
||||
{
|
||||
throw new ServiceException("板块性质名称不能重复");
|
||||
}
|
||||
if (dbModel == null)
|
||||
{
|
||||
throw new ServiceException("数据不存在");
|
||||
}
|
||||
dbModel.Name = model.Name;
|
||||
dbModel.OptId = model.OptId;
|
||||
dbModel.OptName = model.OptName;
|
||||
}
|
||||
else if (model.Group < 1 || model.Group > 5)
|
||||
{
|
||||
throw new ServiceException("group参数无效:" + model.Group);
|
||||
}
|
||||
else if (DbContext.UnderlyingBlockConfig.Any(n => n.id != model.id && n.Group == model.Group && n.Name == model.Name))
|
||||
{
|
||||
throw new ServiceException("板块性质名称不能重复");
|
||||
}
|
||||
else
|
||||
{
|
||||
DbContext.UnderlyingBlockConfig.Add(dbModel = model);
|
||||
}
|
||||
|
||||
dbModel.OptDate = DateTime.Now;
|
||||
|
||||
return DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
public int RemoveDatas(int optId, string optName, params int[] ids)
|
||||
{
|
||||
if (ids == null || !ids.Any()) return 0;
|
||||
var datas = DbContext.UnderlyingBlockConfig.Where(n => ids.Contains(n.id)).ToArray();
|
||||
foreach (var data in datas)
|
||||
{
|
||||
data.Group = -1;
|
||||
data.OptId = optId;
|
||||
data.OptName = optName;
|
||||
data.OptDate = DateTime.Now;
|
||||
}
|
||||
return DbContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,688 @@
|
||||
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;
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
using YLErp.Configuration;
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 标的分红率服务
|
||||
/// </summary>
|
||||
public class UnderlyingDividenRateService : YLBaseService
|
||||
{
|
||||
public UnderlyingDividenRateService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取标的分红率
|
||||
/// </summary>
|
||||
public UnderlyingDividenRateResult GetDividenRate(UnderlyingDividenRateRequest req)
|
||||
{
|
||||
if (req is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(req));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(req.UnderlyingCode))
|
||||
{
|
||||
throw new ServiceException("缺少标的代码");
|
||||
}
|
||||
|
||||
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(req.UnderlyingCode);
|
||||
|
||||
if (um == null)
|
||||
{
|
||||
throw new ServiceException("标的信息未找到:" + req.UnderlyingCode);
|
||||
}
|
||||
|
||||
var qry = from x in DbContext.dividendrate_record
|
||||
where x.TradeType.Contains(req.TradeType)
|
||||
&& req.ValueDate >= x.ValueDate
|
||||
&& (x.OptionType == req.OptionType || x.OptionType == "全部")
|
||||
select x;
|
||||
var list = qry.ToList();
|
||||
var record = list.Where(x => x.UnderlyingCode.Split(',').Any(code => code == req.UnderlyingCode))
|
||||
.OrderByDescending(x => x.OptDate).ThenByDescending(x => x.ValueDate);
|
||||
|
||||
if (record.Any())
|
||||
{
|
||||
return new UnderlyingDividenRateResult
|
||||
{
|
||||
DividendRate = record.First().DividendRate
|
||||
};
|
||||
}
|
||||
|
||||
var query = from n in DbContext.underlying_manager
|
||||
join m in DbContext.UnderlyingDividend.Where(a => a.ValueDate >= req.ValueDate)
|
||||
on n.id equals m.UnderlyingId into ms
|
||||
from m in ms.DefaultIfEmpty()
|
||||
where n.UnderlyingCode == req.UnderlyingCode
|
||||
select m == null ? n.DividendRate : m.DividendRate;
|
||||
|
||||
return new UnderlyingDividenRateResult
|
||||
{
|
||||
DividendRate = query.FirstOrDefault() ?? 0
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标的分红率请求
|
||||
/// </summary>
|
||||
public class UnderlyingDividenRateRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 标的代码
|
||||
/// </summary>
|
||||
public string UnderlyingCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 取值日期
|
||||
/// </summary>
|
||||
public DateTime ValueDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易类型(国元需要)
|
||||
/// </summary>
|
||||
public string TradeType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 看涨看跌(国元需要)
|
||||
/// </summary>
|
||||
public string OptionType { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标的分红率
|
||||
/// </summary>
|
||||
public class UnderlyingDividenRateResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 标的分红率
|
||||
/// </summary>
|
||||
public double? DividendRate { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
using BaseOUDAL;
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 分红率服务
|
||||
/// </summary>
|
||||
public class UnderlyingDividendService : YLBaseService
|
||||
{
|
||||
public UnderlyingDividendService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取最新分红率
|
||||
/// </summary>
|
||||
public SearchListResult<UnderlyingDividendDto> GetLatestList(UnderlyingDividendQueryModel req)
|
||||
{
|
||||
var predicat = PredicateBuilder.Create<underlying_manager>(n => (n.UnderlyingInstrumentType == "Stock" || n.UnderlyingInstrumentType == "StockIndex"));
|
||||
if (!string.IsNullOrWhiteSpace(req.UnderlyingCode))
|
||||
{
|
||||
predicat = predicat.And(n => n.UnderlyingCode.Contains(req.UnderlyingCode));
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(req.UnderlyingName))
|
||||
{
|
||||
predicat = predicat.And(n => n.UnderlyingName.Contains(req.UnderlyingName));
|
||||
}
|
||||
var query = DbContext.underlying_manager
|
||||
.Where(predicat)
|
||||
.Select(n => new UnderlyingDividendDto
|
||||
{
|
||||
id = n.id,
|
||||
UnderlyingId = n.id,
|
||||
UnderlyingCode = n.UnderlyingCode,
|
||||
UnderlyingName = n.UnderlyingName,
|
||||
DividendRate = n.DividendRate ?? 0
|
||||
});
|
||||
|
||||
if (string.IsNullOrEmpty(req.sidx))
|
||||
{
|
||||
query = query.OrderBy(n => n.UnderlyingCode);
|
||||
}
|
||||
|
||||
return query.ToSearchList(req);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取历史分红率
|
||||
/// </summary>
|
||||
public IEnumerable<UnderlyingDividendDto> GetHisList(string underlyingCode)
|
||||
{
|
||||
if (string.IsNullOrEmpty(underlyingCode))
|
||||
{
|
||||
return Enumerable.Empty<UnderlyingDividendDto>();
|
||||
}
|
||||
|
||||
var query = from m in DbContext.underlying_manager
|
||||
join n in DbContext.UnderlyingDividend on m.id equals n.UnderlyingId
|
||||
where m.UnderlyingCode == underlyingCode
|
||||
orderby n.ValueDate descending
|
||||
select new UnderlyingDividendDto
|
||||
{
|
||||
id = n.id,
|
||||
UnderlyingId = n.id,
|
||||
UnderlyingCode = m.UnderlyingCode,
|
||||
UnderlyingName = m.UnderlyingName,
|
||||
DividendRate = n.DividendRate,
|
||||
ValueDate = n.ValueDate,
|
||||
OptDate = n.OptDate,
|
||||
OptId = n.OptId,
|
||||
OptName = n.OptName
|
||||
};
|
||||
return query.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取最新分红率
|
||||
/// </summary>
|
||||
public UnderlyingDividendDto GetLatestDetail(string underlyingCode)
|
||||
{
|
||||
var query = DbContext.underlying_manager
|
||||
.Where(n => n.UnderlyingCode == underlyingCode)
|
||||
.Select(n => new UnderlyingDividendDto
|
||||
{
|
||||
id = n.id,
|
||||
UnderlyingId = n.id,
|
||||
UnderlyingCode = n.UnderlyingCode,
|
||||
UnderlyingName = n.UnderlyingName,
|
||||
DividendRate = n.DividendRate ?? 0
|
||||
});
|
||||
return query.FirstOrDefault();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存分红率
|
||||
/// </summary>
|
||||
public UnderlyingDividend SaveData(UnderlyingDividendDto model)
|
||||
{
|
||||
if (string.IsNullOrEmpty(model?.UnderlyingCode))
|
||||
{
|
||||
throw new ServiceException("股票代码不能为空");
|
||||
}
|
||||
|
||||
var udm = DbContext.underlying_manager.FirstOrDefault(n => n.UnderlyingCode == model.UnderlyingCode);
|
||||
if (udm == null)
|
||||
{
|
||||
throw new ServiceException("股票信息不存在");
|
||||
}
|
||||
|
||||
udm.DividendRate = model.DividendRate;
|
||||
|
||||
var valueDate = BLL.valuedateBLL.ValueDate;
|
||||
if (valueDate < DateTime.Today) valueDate = DateTime.Today;
|
||||
var dbModel = DbContext.UnderlyingDividend.FirstOrDefault(n => n.UnderlyingId == udm.id && n.ValueDate == valueDate);
|
||||
if (dbModel == null)
|
||||
{
|
||||
dbModel = new UnderlyingDividend
|
||||
{
|
||||
UnderlyingId = udm.id,
|
||||
ValueDate = valueDate
|
||||
};
|
||||
DbContext.UnderlyingDividend.Add(dbModel);
|
||||
}
|
||||
|
||||
dbModel.DividendRate = model.DividendRate;
|
||||
dbModel.OptId = model.OptId;
|
||||
dbModel.OptName = model.OptName;
|
||||
dbModel.OptDate = DateTime.Now;
|
||||
|
||||
DbContext.SaveChanges();
|
||||
|
||||
return dbModel;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class UnderlyingDividendQueryModel : BaseSearchReq
|
||||
{
|
||||
public string UnderlyingName { get; set; }
|
||||
|
||||
public string UnderlyingCode { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
using System.Text;
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 标的数据帮助类
|
||||
/// </summary>
|
||||
public static class UnderlyingHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取组合标的品种对象
|
||||
/// </summary>
|
||||
public static Variety GetSyntheticVariety()
|
||||
{
|
||||
var variety = DataCacheProvider.GetVarietyDataSource().AsQueryable()
|
||||
.FirstOrDefault(v => v.VarietyCode == "组合标的");
|
||||
|
||||
if (variety != null)
|
||||
{
|
||||
return variety;
|
||||
}
|
||||
|
||||
lock (DataCacheProvider.GetVarietyDataSource())
|
||||
{
|
||||
using (var db = DbContextFactory.GetYLDbContext())
|
||||
{
|
||||
variety = db.variety.FirstOrDefault(n => n.VarietyCode == "组合标的");
|
||||
|
||||
if (variety != null)
|
||||
{
|
||||
return variety;
|
||||
}
|
||||
|
||||
variety = new Variety()
|
||||
{
|
||||
VarietyCode = "组合标的",
|
||||
VarietyName = "组合标的",
|
||||
TradingMarketId = 0,
|
||||
TradeUnit = "1手/份",
|
||||
QuoteUnit = "元(人民币)/份",
|
||||
DeliveryType = "",
|
||||
HasNightMarket = false,
|
||||
ShortName = "组合标的",
|
||||
CommissionType = "固定",
|
||||
CloseTodayCommissionType = "固定",
|
||||
//UnderlyingInstrumentType = "CommodityFutures",
|
||||
VolatilityRate = "",
|
||||
VolatilityAdjust = 0,
|
||||
AssetType = "",
|
||||
OptId = 0,
|
||||
OptName = "系统",
|
||||
OptDate = DateTime.Now,
|
||||
};
|
||||
|
||||
db.variety.Add(variety);
|
||||
db.SaveChanges();
|
||||
|
||||
return variety;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取篮子标的品种对象
|
||||
/// </summary>
|
||||
public static Variety GetBasketVariety()
|
||||
{
|
||||
return DataCacheProvider.GetVarietyDataSource().AsQueryable()
|
||||
.FirstOrDefault(v => v.VarietyCode == "篮子标的") ??
|
||||
new Variety
|
||||
{
|
||||
VarietyCode = "篮子标的",
|
||||
VarietyName = "篮子标的",
|
||||
QuoteUnit = "元(人民币)/股",
|
||||
TradeUnit = "100股/手"
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取标的品种代码 例:BU,BU-CU
|
||||
/// </summary>
|
||||
/// <param name="underlyingCode"></param>
|
||||
/// <returns></returns>
|
||||
public static string GetUnderlyingVarietyCode(string underlyingCode)
|
||||
{
|
||||
var ret = "";
|
||||
var un = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode);
|
||||
if (un != null)
|
||||
{
|
||||
if (un.UnderlyingType == "组合标的")
|
||||
{
|
||||
var synthetic = DataCacheProvider.GetUnderlyingDataSource().GetSyntheticUnderlying(underlyingCode);
|
||||
if (synthetic != null)
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var va1 = DataCacheProvider.GetVariety(synthetic.UnderlyingCode1);
|
||||
var va2 = DataCacheProvider.GetVariety(synthetic.UnderlyingCode2);
|
||||
var va3 = DataCacheProvider.GetVariety(synthetic.UnderlyingCode3);
|
||||
var va4 = DataCacheProvider.GetVariety(synthetic.UnderlyingCode4);
|
||||
if (va1 != null)
|
||||
{
|
||||
sb.Append(va1.VarietyCode).Append('-');
|
||||
}
|
||||
if (va2 != null)
|
||||
{
|
||||
sb.Append(va2.VarietyCode).Append('-');
|
||||
}
|
||||
if (va3 != null)
|
||||
{
|
||||
sb.Append(va3.VarietyCode).Append('-');
|
||||
}
|
||||
if (va4 != null)
|
||||
{
|
||||
sb.Append(va4.VarietyCode).Append('-');
|
||||
}
|
||||
ret = sb.ToString().Substring(0, sb.Length - 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var va = DataCacheProvider.GetVariety(un.UnderlyingCode);
|
||||
ret = va.VarietyCode;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
using System.Text;
|
||||
using YLErp.BLL;
|
||||
using YLErp.Models;
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
public class UnderlyingHisDataService : YLBaseService
|
||||
{
|
||||
public UnderlyingHisDataService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public UnderlyingHisDataService(YLBaseService baseService) : base(baseService)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新标的历史数据
|
||||
/// </summary>
|
||||
public int AddOrUpdateHisData(UnderlyingHisDataAddOrUpdateRequest req, bool saveChanges = true)
|
||||
{
|
||||
if (req is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(req));
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(req.UnderlyingCode))
|
||||
{
|
||||
throw new ServiceException("标的代码 必须有值");
|
||||
}
|
||||
|
||||
if (saveChanges && !DbContext.underlying_manager.Any(n => n.UnderlyingCode == req.UnderlyingCode))
|
||||
{
|
||||
throw new ServiceException("标的数据 不存在");
|
||||
}
|
||||
|
||||
switch (req.ValueType)
|
||||
{
|
||||
case nameof(MarginParamModel.MarginRate):
|
||||
case nameof(MarginParamModel.UpDownLimit):
|
||||
case nameof(MarginParamModel.VolatilityRate): break;
|
||||
default: throw new ServiceException("ValueType 不支持:" + req.ValueType);
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(req.ValueFlag))
|
||||
{
|
||||
req.ValueFlag = "F";
|
||||
}
|
||||
else if (req.ValueFlag != "F" && req.ValueFlag != "%")
|
||||
{
|
||||
throw new ServiceException("ValueFlag 不支持");
|
||||
}
|
||||
|
||||
var hisdata = DbContext.UnderlyingHisData.OrderByDescending(n => n.ValueDate).FirstOrDefault(
|
||||
n => n.UnderlyingCode == req.UnderlyingCode && n.ValueDate <= req.ValueDate && n.ValueType == req.ValueType);
|
||||
|
||||
if (hisdata != null)
|
||||
{
|
||||
//如果新值和旧值一致则不需要处理
|
||||
var newValue = req.Value;
|
||||
if (newValue.HasValue && Math.Abs(newValue.Value - hisdata.Value) < 1e-6)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
//新值为null并且为第一条时清掉
|
||||
if (!newValue.HasValue && hisdata.ValueDate == req.ValueDate
|
||||
&& !DbContext.UnderlyingHisData.Any(n => n.UnderlyingCode == req.UnderlyingCode && n.ValueDate < req.ValueDate && n.ValueType == req.ValueType))
|
||||
{
|
||||
DbContext.UnderlyingHisData.Remove(hisdata);
|
||||
return saveChanges ? DbContext.SaveChanges() : 0;
|
||||
}
|
||||
}
|
||||
else if (!req.Value.HasValue)
|
||||
{
|
||||
return 0; //如果没有历史数据并且新值为null
|
||||
}
|
||||
|
||||
if (hisdata == null || hisdata.ValueDate < req.ValueDate)
|
||||
{
|
||||
hisdata = new UnderlyingHisData
|
||||
{
|
||||
UnderlyingCode = req.UnderlyingCode,
|
||||
ValueDate = req.ValueDate,
|
||||
ValueType = req.ValueType
|
||||
};
|
||||
|
||||
DbContext.UnderlyingHisData.Add(hisdata);
|
||||
}
|
||||
|
||||
SetDBModelOpt(hisdata);
|
||||
|
||||
hisdata.Value = req.Value ?? 0;
|
||||
|
||||
hisdata.ValueFlag = req.Value.HasValue ? req.ValueFlag : "N";
|
||||
|
||||
return saveChanges ? DbContext.SaveChanges() : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除标的历史数据
|
||||
/// </summary>
|
||||
public int RemoveHisData(string underlyingCode, DateTime valueDate, string valueType)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(underlyingCode) || string.IsNullOrWhiteSpace(valueType))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
valueDate = valueDate.Date;
|
||||
|
||||
var data = DbContext.UnderlyingHisData.FirstOrDefault(
|
||||
n => n.UnderlyingCode == underlyingCode && n.ValueDate == valueDate && n.ValueType == valueType);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
DbContext.UnderlyingHisData.Remove(data);
|
||||
return DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 回写历史数据到主表
|
||||
/// </summary>
|
||||
public int BackHisDataToMainTable()
|
||||
{
|
||||
var db = DbContextFactory.GetYLDbContext();
|
||||
var valueDate = valuedateBLL.ValueDate;
|
||||
var startDate = valuedateBLL.ValueDate.AddDays(-3);
|
||||
var uhgQuery = from a in db.UnderlyingHisData
|
||||
where a.ValueDate >= startDate && a.ValueDate <= valueDate
|
||||
group a by new
|
||||
{
|
||||
a.UnderlyingCode,
|
||||
a.ValueType
|
||||
} into aa
|
||||
select new
|
||||
{
|
||||
aa.Key.UnderlyingCode,
|
||||
aa.Key.ValueType,
|
||||
ValueDate = aa.Max(n => n.ValueDate)
|
||||
};
|
||||
|
||||
var uhQuery = from a in uhgQuery
|
||||
join b in db.UnderlyingHisData on new { a.UnderlyingCode, a.ValueType, a.ValueDate } equals new { b.UnderlyingCode, b.ValueType, b.ValueDate }
|
||||
select new
|
||||
{
|
||||
b.UnderlyingCode,
|
||||
b.Value,
|
||||
b.ValueType,
|
||||
b.ValueFlag
|
||||
};
|
||||
|
||||
var hisdatas = uhQuery.ToArray();
|
||||
|
||||
if (!hisdatas.Any())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder(1000);
|
||||
|
||||
const string sqlfmtMarginRate = "update underlying_manager set MarginRate='{0}' WHERE UnderlyingCode='{1}';";
|
||||
const string sqlfmtUpDownLimit = "update underlying_manager set UpDownLimit='{0}' WHERE UnderlyingCode='{1}';";
|
||||
const string sqlfmtVolatilityRate = "update underlying_manager set VolatilityRate='{0}' WHERE UnderlyingCode='{1}';";
|
||||
|
||||
//new underlying_manager().MarginRate;
|
||||
|
||||
foreach (var item in hisdatas)
|
||||
{
|
||||
switch (item.ValueType)
|
||||
{
|
||||
case nameof(MarginParamModel.MarginRate):
|
||||
if (item.ValueFlag == "N")
|
||||
{
|
||||
sb.AppendFormat("update underlying_manager set MarginRate=null WHERE UnderlyingCode='{0}';", item.UnderlyingCode).AppendLine();
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendFormat(sqlfmtMarginRate, item.Value.ToString("0.0#####"), item.UnderlyingCode).AppendLine();
|
||||
}
|
||||
break;
|
||||
case nameof(MarginParamModel.UpDownLimit):
|
||||
var fmt = item.ValueFlag == "%" ? "0.0###%" : "0.0#####";
|
||||
sb.AppendFormat(sqlfmtUpDownLimit, item.ValueFlag == "N" ? "" : item.Value.ToString(fmt), item.UnderlyingCode).AppendLine();
|
||||
break;
|
||||
case nameof(MarginParamModel.VolatilityRate):
|
||||
sb.AppendFormat(sqlfmtVolatilityRate, item.ValueFlag == "N" ? "" : item.Value.ToString("0.0###%"), item.UnderlyingCode).AppendLine();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var sql = sb.ToString();
|
||||
LogFactory.GetLogger("回写标的历史数据到主表").Info(sql);
|
||||
return DbContext.Database.ExecuteSqlRaw(sql);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class UnderlyingHisDataAddOrUpdateRequest
|
||||
{
|
||||
public string UnderlyingCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 使用MarginParamModel的属性字段
|
||||
/// </summary>
|
||||
public string ValueType { get; set; }
|
||||
|
||||
public string ValueFlag { get; set; }
|
||||
|
||||
public DateTime ValueDate { get; set; }
|
||||
|
||||
public double? Value { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
using System.Data;
|
||||
using YLErp.Commons;
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
public class UnderlyingImportService : YLBaseService
|
||||
{
|
||||
public UnderlyingImportService(OptUserInfo userInfo) : base(userInfo) { }
|
||||
|
||||
public void ImportExcel(Stream streamIn, out int totalNum, out int successNum)
|
||||
{
|
||||
totalNum = 0;
|
||||
successNum = 0;
|
||||
|
||||
int rowIndex = 0;
|
||||
try
|
||||
{
|
||||
var ds = Office.ExcelHelper.ReadExcelAsDataSet(streamIn, new[] { 0 }, 1);
|
||||
|
||||
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);
|
||||
|
||||
totalNum = table.Rows.Count - rowIndex;
|
||||
|
||||
foreach (var row in table.Rows.Cast<DataRow>())
|
||||
{
|
||||
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
|
||||
{
|
||||
totalNum--;
|
||||
continue;
|
||||
}
|
||||
|
||||
reader.SetDataRow(row);
|
||||
|
||||
using (var trans = BeginTransaction())
|
||||
{
|
||||
//映射导入数据
|
||||
var um = MapUnderlying(reader);
|
||||
|
||||
//保存数据
|
||||
new UnderlyingDalService(OptUser).SaveUnderlyingData(um);
|
||||
successNum++;
|
||||
|
||||
trans.Commit();
|
||||
}
|
||||
rowIndex++;
|
||||
}
|
||||
}
|
||||
catch (ServiceException se)
|
||||
{
|
||||
if (se.Tag != null) throw;
|
||||
throw new ServiceException($"第{rowIndex + 2}行,发生错误:{se.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private underlying_manager MapUnderlying(DataRowReader reader)
|
||||
{
|
||||
var umVariety = reader.GetString("标的品种", true);
|
||||
var variety = DataCacheProvider.GetVarietyDataSource().AsQueryable().Where(o => o.VarietyName == umVariety || o.VarietyCode == umVariety).FirstOrDefault();
|
||||
if (variety == null)
|
||||
{
|
||||
throw new Exception("未找到品种:" + umVariety);
|
||||
}
|
||||
var instrumentTypeCn = reader.GetString("标的小类(资产类型)", true);
|
||||
//var markShortName = reader.GetString("交易所", true);
|
||||
//var market = DataCacheProvider.GetMarketDataSource().AsQueryable().Where(o => o.MarketShortName == markShortName || o.MarketName== markShortName || o.ExchangeNo == markShortName).FirstOrDefault();
|
||||
//if (market == null)
|
||||
//{
|
||||
// throw new Exception("未找到交易所:" + markShortName);
|
||||
//}
|
||||
|
||||
var um = new underlying_manager()
|
||||
{
|
||||
//MarketCode = market.ExchangeNo,
|
||||
UnderlyingCode = reader.GetString("标的代码", true),
|
||||
UnderlyingName = reader.GetString("标的名称", true),
|
||||
UnderlyingEnName = reader.GetString("标的英文名", false),
|
||||
UnderlyingTypeId = variety.id,
|
||||
UnderlyingInstrumentType = ConsGlobal.InstrumentType.GetFromDesc(instrumentTypeCn),
|
||||
BBGTicker = reader.GetString("BBGTicker", false),
|
||||
ContractSize = reader.GetDouble("合约乘数", false) ?? 0,
|
||||
MaturityDate = reader.GetDate("标的到期日", false),
|
||||
CloseDate = reader.GetDate("标的交割日", false),
|
||||
UnderlyingDesc = reader.GetString("描述", false),
|
||||
LaunchState = "1",
|
||||
UnderlyingStatus = "正常运行",
|
||||
OptId = UserId,
|
||||
OptName = UserName,
|
||||
OptDate = DateTime.Now
|
||||
};
|
||||
|
||||
return um;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,167 @@
|
||||
using YLErp.BLL.Calculation;
|
||||
using YLErp.QdpModule;
|
||||
|
||||
namespace YLErp.BLL
|
||||
{
|
||||
public class underlying_main_contractBLL
|
||||
{
|
||||
public static bool IsListOld = true;
|
||||
|
||||
private static List<underlying_main_contract> Allunderlying_main_contractModel = null;
|
||||
|
||||
public static List<underlying_main_contract> GetAllunderlying_main_contractModel()
|
||||
{
|
||||
if (IsListOld)
|
||||
{
|
||||
using (YLContext con = new YLContext())
|
||||
{
|
||||
Allunderlying_main_contractModel = con.underlying_main_contract.ToList();
|
||||
}
|
||||
IsListOld = false;
|
||||
}
|
||||
return Allunderlying_main_contractModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 过滤掉不符合规则的标的
|
||||
/// 国君规则: 标的到期日前一个月15号必需大于输入的到期日参数maturitydate(到期日为当前时间一个月后的第一个工作日)
|
||||
/// </summary>
|
||||
public static List<underlying_manager> GetGtja_MaturityUnderlying(List<underlying_manager> tofilterUnderlyings, DateTime maturityDate)
|
||||
{
|
||||
//调整:
|
||||
//原来的逻辑是:underlyingMaturityDate > (maturityDate + 1 month).15th
|
||||
//修正后的逻辑是: (underlyingMaturityDate - 1 month).15th > maturityDate
|
||||
var underlyings = new List<underlying_manager>();
|
||||
foreach (var x in tofilterUnderlyings)
|
||||
{
|
||||
if (x.IsVirtualContract() || !x.IsFutures())
|
||||
{
|
||||
underlyings.Add(x);
|
||||
}
|
||||
else
|
||||
{
|
||||
var underlyingMaturityDate = DateTime.Now;
|
||||
if (x.MaturityDate == null)
|
||||
{
|
||||
underlyingMaturityDate = QdpHelper.defaultMaturityDateFromContract(x.UnderlyingCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
underlyingMaturityDate = CalculatorHelper.GetContractMaturityDateForQuote(x.MaturityDate.Value, x.UnderlyingCode);
|
||||
}
|
||||
|
||||
var underlyingCodeArray = x.UnderlyingCode.TakeWhile(c => char.IsLetter(c)).ToArray();
|
||||
|
||||
var mainUnderlyingCode = new string(underlyingCodeArray) + "00";
|
||||
int.TryParse(x.UnderlyingCode.Substring(x.UnderlyingCode.Length - 2), out var monthInCode);
|
||||
var beforUnderlyingCode = x.UnderlyingCode.Substring(0, x.UnderlyingCode.Length - 2) + (monthInCode - 1).ToString("00");
|
||||
var mainUnderlying = YLErp.Modules.DataCacheProvider.GetUnderlyingDataSource().GetData(mainUnderlyingCode);
|
||||
//是否为“主力合约”,或上一个为“主力合约”
|
||||
var IsMainUnderlying = x.UnderlyingCode == mainUnderlying.TradeCode || beforUnderlyingCode == mainUnderlying.TradeCode;
|
||||
|
||||
|
||||
|
||||
var checkDate = underlyingMaturityDate;
|
||||
//做个月份补丁,如果是1809默认是9月份
|
||||
//没有考虑到1月这种情况,需要测试
|
||||
//if (int.TryParse(x.UnderlyingCode.Substring(x.UnderlyingCode.Length - 2), out int tempData) && tempData > 1 && tempData <= 12 && x.UnderlyingInstrumentType != "Stock")
|
||||
//{
|
||||
// checkDate = new DateTime(underlyingMaturityDate.Year, tempData, 15);
|
||||
//}
|
||||
if (IsMainUnderlying)
|
||||
{
|
||||
//当前所报的合约的到期日必须小于该合约的到期日-10个交易日
|
||||
checkDate = QdpCalendarHelper.BizDayShift(checkDate, -10);
|
||||
if (checkDate >= maturityDate)
|
||||
{
|
||||
underlyings.Add(x);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
checkDate = new DateTime(underlyingMaturityDate.Year, underlyingMaturityDate.Month, 15);
|
||||
checkDate = checkDate.AddMonths(-1);
|
||||
if (PS.Config.Company==Configuration.CompanyEnum.国贸启润)
|
||||
{
|
||||
checkDate = underlyingMaturityDate;
|
||||
}
|
||||
if (checkDate >= maturityDate)
|
||||
{
|
||||
underlyings.Add(x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return underlyings;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取给定到期日的平值期权报价列表
|
||||
/// 这个函数需要给Web和API使用,因此不使用缓存,直接从数据库查询
|
||||
/// 国君规则: 标的到日期前一个月15号必需大于 maturitydate(到期日为当前时间一个月后的第一个工作日)
|
||||
/// </summary>
|
||||
/// <param name="maturityDate">报价到期日</param>
|
||||
/// <param name="onlyMainContract">是否只包含主力合约</param>
|
||||
public static List<underlying_manager> GetDefaultAtMoneyQuoteList(DateTime maturityDate, bool onlyMainContract = true)
|
||||
{
|
||||
var del = new char[] { ',' };
|
||||
|
||||
using (var db = new YLContext())
|
||||
{
|
||||
//筛选所有需要报价的品种,并将其对应的合约代码加入codes
|
||||
var activeAssetList = GetAllunderlying_main_contractModel().Where(x => x.NeedQuote == 1).OrderBy(n => n.UnderlyingType).ToList();
|
||||
string preUnderlyingType = null;
|
||||
var unCodeSet = new HashSet<string>();
|
||||
foreach (var asset in activeAssetList.ToArray())
|
||||
{
|
||||
if (preUnderlyingType == asset.UnderlyingType ||
|
||||
string.IsNullOrWhiteSpace(asset.UnderlyingType) ||
|
||||
string.IsNullOrWhiteSpace(asset.UnderlyingCode))
|
||||
{
|
||||
activeAssetList.Remove(asset);
|
||||
}
|
||||
else
|
||||
{
|
||||
preUnderlyingType = asset.UnderlyingType;
|
||||
var arr = asset.UnderlyingCode.Split(del, StringSplitOptions.RemoveEmptyEntries);
|
||||
foreach (var item in arr)
|
||||
{
|
||||
unCodeSet.Add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//需要获取underlying最新的价格,所以需要从数据库读取
|
||||
var underlyings = db.underlying_manager.Where(x => unCodeSet.Contains(x.UnderlyingCode) && x.LaunchState == "1").ToList();
|
||||
underlyings = GetGtja_MaturityUnderlying(underlyings, maturityDate);
|
||||
|
||||
if (onlyMainContract)
|
||||
{
|
||||
var quoteContracts = new Dictionary<string, underlying_manager>();
|
||||
//每个品种,满足条件的合约中到日期最早的那个
|
||||
foreach (var underlying in underlyings)
|
||||
{
|
||||
if ((!quoteContracts.ContainsKey(underlying.UnderlyingType))
|
||||
|| underlying.MaturityDate < quoteContracts[underlying.UnderlyingType].MaturityDate)
|
||||
{
|
||||
quoteContracts[underlying.UnderlyingType] = underlying;
|
||||
}
|
||||
}
|
||||
underlyings = quoteContracts.Values.ToList();
|
||||
}
|
||||
|
||||
var dic = activeAssetList.ToDictionary(n => n.UnderlyingType);
|
||||
foreach (var un in underlyings)
|
||||
{
|
||||
if (dic.TryGetValue(un.UnderlyingType, out var asset))
|
||||
{
|
||||
un.order = asset.OrderId;
|
||||
}
|
||||
}
|
||||
|
||||
underlyings.Sort((x, y) => (x.order ?? 0) - (y.order ?? 0));
|
||||
return underlyings;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
using BaseOUDAL;
|
||||
using YLErp.Model;
|
||||
using YLErp.Modules.VolatilityModule;
|
||||
using YLErp.Modules.VolatilityModule.SkewMapVolModule;
|
||||
using YLErp.QdpModule;
|
||||
using YLErp.QdpModule.Constants;
|
||||
|
||||
namespace YLErp.BLL
|
||||
{
|
||||
public class underlying_main_contract_historyBLL
|
||||
{
|
||||
public static readonly List<string> ShowExpires;
|
||||
public static readonly List<string> 有色金属ShowExpires;
|
||||
|
||||
static underlying_main_contract_historyBLL()
|
||||
{
|
||||
if (!PS.Config.ErpElement.SkewMapVolConstruction)
|
||||
{
|
||||
ShowExpires = new List<string> { "2W", "1M", "3M" };
|
||||
有色金属ShowExpires = new List<string> { "2W", "1M", "2M" };
|
||||
}
|
||||
else
|
||||
{
|
||||
ShowExpires = new List<string> { "1M", "3M", "6M" };
|
||||
有色金属ShowExpires = new List<string> { "1M", "3M", "6M" };
|
||||
}
|
||||
}
|
||||
|
||||
public static List<VolatilityQuotation> GetVolatilityQuotation(int userId, IEnumerable<flat_price_quotation> quotationList, string userGroup = null)
|
||||
{
|
||||
var VQ = new List<VolatilityQuotation>();
|
||||
if (string.IsNullOrEmpty(userGroup))
|
||||
{
|
||||
userGroup = UserBLL.GetUserGroup(userId);
|
||||
}
|
||||
var vollist = new VolatilityQueryService(OptUserInfo.SystemUser)
|
||||
.GetVolatilities(new BatchVolatilityRequest
|
||||
{
|
||||
QuotationDate = valuedateBLL.ValueDate,
|
||||
VolTypes = ConsVolInfos.subTradeVolType,
|
||||
UnderlyingCodes = quotationList.Select(O => O.UnderlyingCode).ToArray(),
|
||||
UserGroup = userGroup,
|
||||
TradeVolWithBidAsk = false
|
||||
}, true);
|
||||
var exDate = QdpCalendarHelper.GetNonHoliday(valuedateBLL.ValueDate.AddMonths(1).AddDays(-1));
|
||||
var exerciseDate = exDate;
|
||||
var quotationUnderlyinglist = underlying_main_contractBLL.GetDefaultAtMoneyQuoteList(exDate);
|
||||
|
||||
quotationList = quotationList.Where(q =>
|
||||
quotationUnderlyinglist.Any(u => string.Equals(u.UnderlyingCode, q.UnderlyingCode, StringComparison.OrdinalIgnoreCase))).OrderBy(o => o.order).ToList();
|
||||
|
||||
var activeAsset = underlying_main_contractBLL.GetAllunderlying_main_contractModel().Where(x => x.NeedQuote == 1);
|
||||
|
||||
foreach (var qu in quotationList)
|
||||
{
|
||||
var singleVQ = new VolatilityQuotation() { MarketName = qu.MarketName, UnderlyingMainCode = qu.UnderlyingCode, UnderlyingType = qu.UnderlyingType };
|
||||
var underlying = quotationUnderlyinglist.FirstOrDefault(u => string.Equals(u.UnderlyingCode, qu.UnderlyingCode, StringComparison.OrdinalIgnoreCase));
|
||||
singleVQ.CommodityCode = underlying.CommodityCode;
|
||||
var checkExpires = ShowExpires;
|
||||
if (underlying_managerBLL.IsYouSeJinShu(qu.UnderlyingCode))
|
||||
{
|
||||
checkExpires = 有色金属ShowExpires;
|
||||
}
|
||||
var contractUnder = activeAsset.FirstOrDefault(q => q.UnderlyingType == qu.UnderlyingType);
|
||||
//var tt = activeAsset.Where(v => v.UnderlyingCode == qu.UnderlyingCode).ToList();
|
||||
//var ttt = quotationUnderlyinglist.Where(q => q.UnderlyingType == "棕榈油").ToList();
|
||||
var contractVol = new List<volatility>();
|
||||
if (contractUnder != null && vollist != null)
|
||||
{
|
||||
contractVol = vollist.Where(v => contractUnder.UnderlyingCodeList.Contains(v.ContractCode)).ToList();
|
||||
}
|
||||
|
||||
volatility askVolTable = null;
|
||||
volatility bidVolTable = null;
|
||||
if (PS.Config.ErpElement.SkewMapVolConstruction)
|
||||
{
|
||||
var req = new SkewVolRequest
|
||||
{
|
||||
VolType = null,
|
||||
valueDate = valuedateBLL.ValueDate,
|
||||
Strike = qu.SpotPrice ?? 0,
|
||||
UnderlyingCode = underlying.UnderlyingCode
|
||||
};
|
||||
req.VolType = "报价Ask";
|
||||
askVolTable = SkewVolQueryService.GetVol(userId, req);
|
||||
req.VolType = "报价Bid";
|
||||
bidVolTable = SkewVolQueryService.GetVol(userId, req);
|
||||
}
|
||||
else
|
||||
{
|
||||
askVolTable = SetVolQuotationTable(contractVol, qu, "报价Ask", checkExpires);
|
||||
bidVolTable = SetVolQuotationTable(contractVol, qu, "报价Bid", checkExpires);
|
||||
}
|
||||
|
||||
var volReq = new InterpolatedVolReq()
|
||||
{
|
||||
strike = qu.SpotPrice ?? 0,
|
||||
isMoneynessOption = false,
|
||||
exerciseDate = exerciseDate,
|
||||
valueDate = valuedateBLL.ValueDate,
|
||||
spot = qu.SpotPrice ?? 0,
|
||||
volSurfaceType = askVolTable.VolSurfaceMode
|
||||
};
|
||||
|
||||
var askeGroup = new List<ExpireGroup>();
|
||||
if (askVolTable.VolTable != null)
|
||||
{
|
||||
askeGroup = askVolTable.VolTable.GroupBy(v => v.Expire).Select(v => new ExpireGroup { Expire = v.Key, Sv = v.ToList() }).ToList();
|
||||
}
|
||||
|
||||
var bideGroup = new List<ExpireGroup>();
|
||||
if (bidVolTable.VolTable != null)
|
||||
{
|
||||
bideGroup = bidVolTable.VolTable.GroupBy(v => v.Expire).Select(v => new ExpireGroup { Expire = v.Key, Sv = v.ToList() }).ToList();
|
||||
}
|
||||
|
||||
var BidAskMatureData = new List<BidAskMatureData>();
|
||||
|
||||
foreach (var expire in checkExpires)
|
||||
{
|
||||
var askvol = double.NaN;
|
||||
var bidvol = double.NaN;
|
||||
var askGroup = askeGroup.FirstOrDefault(a => a.Expire == expire);
|
||||
var bidgroup = bideGroup.FirstOrDefault(b => b.Expire == expire);
|
||||
if (askGroup != null)
|
||||
{
|
||||
askvol = QdpVolHelper.GetInterpolatedVolFromNormalSurface(askGroup.Sv, volReq, askVolTable.InterpolationMethod);
|
||||
}
|
||||
else if (!PS.Config.ErpElement.SkewMapVolConstruction)
|
||||
{
|
||||
askvol = QdpVolHelper.GetInterpolatedVolFromNormalSurface(askVolTable.VolTable, volReq, askVolTable.InterpolationMethod);
|
||||
}
|
||||
if (bidgroup != null)
|
||||
{
|
||||
bidvol = QdpVolHelper.GetInterpolatedVolFromNormalSurface(bidgroup.Sv, volReq, bidVolTable.InterpolationMethod);
|
||||
}
|
||||
else if (!PS.Config.ErpElement.SkewMapVolConstruction)
|
||||
{
|
||||
bidvol = QdpVolHelper.GetInterpolatedVolFromNormalSurface(bidVolTable.VolTable, volReq, bidVolTable.InterpolationMethod);
|
||||
}
|
||||
|
||||
var md = new BidAskMatureData() { Expire = expire, AskVol = askvol, BidVol = bidvol };
|
||||
BidAskMatureData.Add(md);
|
||||
}
|
||||
singleVQ.BidAskMatureData = BidAskMatureData;
|
||||
VQ.Add(singleVQ);
|
||||
|
||||
}
|
||||
return VQ;
|
||||
}
|
||||
|
||||
public static volatility SetVolQuotationTable(List<volatility> vollist, flat_price_quotation qu, string voltype, List<string> ShowExpires)
|
||||
{
|
||||
var askVolTable = vollist.FirstOrDefault(v => v.ContractCode == qu.UnderlyingCode && v.VolType == voltype);
|
||||
if (askVolTable == null)
|
||||
{
|
||||
askVolTable = vollist.FirstOrDefault(v => v.ContractCode.Contains(underlying_managerBLL.GetCommodityCodeByUnCode(qu.UnderlyingCode)) && v.VolType == voltype);
|
||||
if (askVolTable == null)
|
||||
{
|
||||
askVolTable = new volatility { VolType = voltype, VolSurfaceMode = "MoneynessVol" };
|
||||
return askVolTable;
|
||||
}
|
||||
}
|
||||
if (string.IsNullOrEmpty(askVolTable.VolSurfaceMode))
|
||||
{
|
||||
askVolTable.VolSurfaceMode = "MoneynessVol";
|
||||
}
|
||||
//需要检查 ShowExpires 里不存在的
|
||||
foreach (var expire in ShowExpires)
|
||||
{
|
||||
if (!askVolTable.VolTable.Any(v => v.Expire == expire))
|
||||
{
|
||||
//不存在则要查找 todo 这边应该找主力合约的波动率
|
||||
var volTable = vollist.FirstOrDefault(v => v.VolTable.Any(vt => vt.Expire == expire) && v.VolType == voltype);
|
||||
if (volTable != null && volTable.VolTable != null)
|
||||
{
|
||||
var vtInner = volTable.VolTable.Where(vt => vt.Expire == expire).ToList();
|
||||
if (vtInner != null)
|
||||
{
|
||||
var vt = askVolTable.VolTable;
|
||||
vt.AddRange(vtInner);
|
||||
askVolTable.Data = vt.ToJson();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return askVolTable;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using YLErp.BLL;
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 报价参数服务
|
||||
/// </summary>
|
||||
public class UnderlyingParameterService : YLBaseService
|
||||
{
|
||||
public UnderlyingParameterService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 初始化标的报价参数
|
||||
/// </summary>
|
||||
public List<underlying_parameter> InitialUnderlyingParameter(int underlyingId)
|
||||
{
|
||||
var list = DbContext.underlying_parameter.AsNoTracking()
|
||||
.Where(u => u.UnderlyingId == underlyingId).ToList();
|
||||
|
||||
//如果没有报价参数,则新增
|
||||
if (!list.Any())
|
||||
{
|
||||
underlying_parameter.defaultQuoteTypes.ForEach(t =>
|
||||
{
|
||||
underlying_parameter up = new underlying_parameter() { NoRiskRate = valuedateBLL.SystemDate.RiskFreeRate * 0.01, Price = 0, Gamma = 0, Rho = 0, Vega = 0, Theta = 0, Delta = 0, UnderlyingId = underlyingId, Type = t, OptDate = DateTime.Now, OptId = UserId, OptName = UserName };
|
||||
DbContext.underlying_parameter.Add(up);
|
||||
list.Add(up);
|
||||
});
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
return list.OrderBy(u => u.Type).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存报价参数
|
||||
/// </summary>
|
||||
public int SaveDatas(IEnumerable<underlying_parameter> list)
|
||||
{
|
||||
if (list is null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
foreach (var data in list)
|
||||
{
|
||||
if (data == null) continue;
|
||||
|
||||
var model = DbContext.underlying_parameter.Find(data.id);
|
||||
|
||||
if (model == null)
|
||||
{
|
||||
throw new ServiceException("更新失败,数据不存在,id:" + data.id);
|
||||
}
|
||||
|
||||
YieldChain.Helpers.ObjectHelper.MapValues(model, data, "ValidState");
|
||||
|
||||
model.OptId = UserId;
|
||||
model.OptName = UserName;
|
||||
model.OptDate = DateTime.Now;
|
||||
}
|
||||
|
||||
return DbContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,512 @@
|
||||
using Qdp.Pricing.Library.Common.Products.Rates;
|
||||
using System.Linq.Expressions;
|
||||
using System.Runtime.Intrinsics.Arm;
|
||||
using YLErp.BLL;
|
||||
using YLErp.Modules.DataProviderModule;
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 标的选项服务
|
||||
/// </summary>
|
||||
public class UnderlyingSelectService : YLBaseService
|
||||
{
|
||||
public UnderlyingSelectService(YLBaseService baseService) : base(baseService)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public UnderlyingSelectService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取标的选项
|
||||
/// </summary>
|
||||
public IEnumerable<UnderlyingSelectItem> GetSelectItems(UnderlyingSelectRequest req)
|
||||
{
|
||||
if (req.MaxShowLength < 1) req.MaxShowLength = 1;
|
||||
|
||||
IEnumerable<UnderlyingSelectItem> datas = null;
|
||||
|
||||
var predicate = BuildPredicate(req);
|
||||
var query = DataCacheProvider.GetUnderlyingDataSource().AsQueryable().Where(predicate).Take(req.MaxShowLength).ToList();
|
||||
if (req.UseForTrading)
|
||||
{
|
||||
List<string> Codes = null;
|
||||
var useWhiteCode = req.BlackLimit > 0 && new StockBlackWhiteService(UserInfo).GetStockBlackWhiteList((Configuration.Enums.LimitRangeEnum)req.BlackLimit, out Codes);
|
||||
|
||||
UnderlyingSelectItem2 convert(underlying_manager n)
|
||||
{
|
||||
var item = new UnderlyingSelectItem2
|
||||
{
|
||||
id = n.id,
|
||||
Code = n.UnderlyingCode,
|
||||
Name = n.CalcTypeIsStock() && !n.IsSynthetic() ? n.UnderlyingName : "",
|
||||
VarietyId = n.UnderlyingTypeId,
|
||||
MaturityDate = n.CalcTypeIsStock() || n.IsCommoditySpot() || !n.MaturityDate.HasValue ? "" : n.MaturityDate.Value.ToString("yyyy-MM-dd"),
|
||||
CountRatio = n.CountRatio,
|
||||
ContractSize = n.ContractSize,
|
||||
Price = n.IsBasket() ? DataCacheProvider.GetUnderlyingDataSource().GetPrice(n.UnderlyingCode) : n.Price ?? 0,
|
||||
IsSynthetic = n.IsSynthetic(),
|
||||
IsBasket = n.IsBasket(),
|
||||
InstrumentType = n.UnderlyingInstrumentType,
|
||||
DividendRate = n.DividendRate,
|
||||
QuoteUnitString = n.QuoteUnitString,
|
||||
BlackWhiteState = req.BlackLimit == 0 ? 0 : useWhiteCode ? 1 : 2,
|
||||
Disallow = req.BlackLimit != 0 && n.IsStock() && !n.IsSynthetic() && !n.IsBasket() && Codes != null && useWhiteCode == Codes.Contains(n.UnderlyingCode),
|
||||
UpDownLimit = n.UpDownLimit,
|
||||
PrevClosePrice = n.PrevClosePrice
|
||||
};
|
||||
if (n.IsBond()&&!string.IsNullOrEmpty(n.ExJson))
|
||||
{
|
||||
var bond = JsonHelper.Deserialize<UnderlyingBond>(n.ExJson);
|
||||
item.Name = n.UnderlyingName;
|
||||
item.UnderlyingFullName=bond.UnderlyingFullName;
|
||||
item.UnderlyingIssuer = bond.UnderlyingIssuer;
|
||||
item.IssueSize = bond.IssueSize;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
datas = query.Select(convert).Take(req.MaxShowLength).ToArray();
|
||||
|
||||
Variety variety = null;
|
||||
|
||||
foreach (UnderlyingSelectItem2 item in datas)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(item.UpDownLimit))
|
||||
{
|
||||
if (variety != null && variety.id == item.VarietyId)
|
||||
{
|
||||
item.UpDownLimit = variety.UpLimit;
|
||||
}
|
||||
else
|
||||
{
|
||||
variety = DataCacheProvider.GetVarietyDataSource().GetData(item.VarietyId);
|
||||
if (variety != null)
|
||||
{
|
||||
item.UpDownLimit = variety.UpLimit;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (Codes == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.IsSynthetic)
|
||||
{
|
||||
var underlyingInfo = DataCacheProvider.GetUnderlyingDataSource().GetSyntheticUnderlying(item.Code);
|
||||
item.Disallow = underlyingInfo.GetUnderlyingCodes().Any(O =>
|
||||
{
|
||||
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(O);
|
||||
return req.BlackLimit != 0 && um.IsStock() && !um.IsSynthetic() && !um.IsBasket() && Codes != null && useWhiteCode == Codes.Contains(O);
|
||||
});
|
||||
}
|
||||
|
||||
if (item.IsBasket)
|
||||
{
|
||||
var underlyingInfo = DataCacheProvider.GetUnderlyingDataSource().GetData(item.Code);
|
||||
var data = JsonHelper.Deserialize<List<BasketUnderlyingItem>>(underlyingInfo.SubData);
|
||||
item.Disallow = data.Any(O =>
|
||||
{
|
||||
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(O.code);
|
||||
return um == null ? true : req.BlackLimit != 0 && um.IsStock() && !um.IsSynthetic() && !um.IsBasket() && Codes != null && useWhiteCode == Codes.Contains(O.code);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var query2 = query.Select(n => new UnderlyingSelectItem
|
||||
{
|
||||
id = n.id,
|
||||
Code = n.UnderlyingCode,
|
||||
Name = ConsGlobal.InstrumentType.CalcTypeIsStock(n.UnderlyingInstrumentType) ? n.UnderlyingName : "",
|
||||
VarietyId = n.UnderlyingTypeId
|
||||
}).Take(req.MaxShowLength);
|
||||
datas = query2.ToArray();
|
||||
}
|
||||
|
||||
if (req.MustRetOne && !datas.Any())
|
||||
{
|
||||
req.MustRetOne = false;
|
||||
req.MaxShowLength = 1;
|
||||
req.FilterCode = null;
|
||||
return GetSelectItems(req);
|
||||
}
|
||||
|
||||
return datas;
|
||||
}
|
||||
|
||||
//创建标的查询预测
|
||||
private Expression<Func<underlying_manager, bool>> BuildPredicate(UnderlyingSelectRequest req)
|
||||
{
|
||||
if (req.UnderlyingId > 0)
|
||||
{
|
||||
return PredicateBuilder.Create<underlying_manager>(n => n.id == req.UnderlyingId);
|
||||
}
|
||||
|
||||
if (req.ExcatCodeFilter)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(req.FilterCode)
|
||||
? PredicateBuilder.False<underlying_manager>()
|
||||
: PredicateBuilder.Create<underlying_manager>(n => n.UnderlyingCode==req.FilterCode);
|
||||
}
|
||||
|
||||
var predicate = PredicateBuilder.True<underlying_manager>();
|
||||
|
||||
//标的品种
|
||||
|
||||
IEnumerable<int> varietyids = null;
|
||||
|
||||
if (req.ClientId > 0)
|
||||
{
|
||||
varietyids = TradeRightProvider.GetClientVarietyIds(req.ClientId);
|
||||
}
|
||||
|
||||
if (req.UseRightFilter)
|
||||
{
|
||||
var varietyids2 = TradeRightProvider.GetUserVarietyIds(UserId);
|
||||
varietyids = varietyids == null ? varietyids2 : varietyids.Concat(varietyids2);
|
||||
}
|
||||
|
||||
if (varietyids != null)
|
||||
{
|
||||
if (!varietyids.Any(n => n > 0))
|
||||
{
|
||||
return PredicateBuilder.False<underlying_manager>();
|
||||
}
|
||||
predicate = predicate.And(n => varietyids.Contains(n.UnderlyingTypeId));
|
||||
}
|
||||
|
||||
//是否启用
|
||||
if (req.CheckLaunch)
|
||||
{
|
||||
predicate = predicate.And(n => n.LaunchState == "1");
|
||||
}
|
||||
|
||||
//资产类型
|
||||
List<string> instTypes = null;
|
||||
if (req.InstrumentTypes != null && req.InstrumentTypes.Any(n => !string.IsNullOrEmpty(n)))
|
||||
{
|
||||
instTypes = req.InstrumentTypes.Where(n => !string.IsNullOrEmpty(n)).ToList();
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(req.Scenario))
|
||||
{
|
||||
if (instTypes == null)
|
||||
{
|
||||
instTypes = new List<string>();
|
||||
}
|
||||
|
||||
if (req.Scenario == "期权交易")
|
||||
{
|
||||
instTypes.AddRange(ConsGlobal.InstrumentType.GetFutureTypes());
|
||||
instTypes.AddRange(ConsGlobal.InstrumentType.GetSpotTypes());
|
||||
instTypes.AddRange(ConsGlobal.InstrumentType.GetStockTypes());
|
||||
}
|
||||
}
|
||||
|
||||
if (instTypes != null)
|
||||
{
|
||||
if (!instTypes.Any())
|
||||
{
|
||||
return PredicateBuilder.False<underlying_manager>();
|
||||
}
|
||||
predicate = predicate.And(n => instTypes.Contains(n.UnderlyingInstrumentType));
|
||||
}
|
||||
|
||||
//组合标的
|
||||
|
||||
if (req.OnlySynthetic)
|
||||
{
|
||||
predicate = predicate.And(n => n.CommodityCode == "组合标的");
|
||||
}
|
||||
else if (!req.IncludeSynthetic)
|
||||
{
|
||||
predicate = predicate.And(n => n.CommodityCode != "组合标的");
|
||||
}
|
||||
|
||||
//篮子标的
|
||||
|
||||
if (req.OnlyBasket)
|
||||
{
|
||||
predicate = predicate.And(n => n.CommodityCode == "篮子标的");
|
||||
}
|
||||
else if (!req.IncludeBasket)
|
||||
{
|
||||
predicate = predicate.And(n => n.CommodityCode != "篮子标的");
|
||||
}
|
||||
|
||||
//过期标的
|
||||
if (req.MinMaturityDate.HasValue)
|
||||
{
|
||||
predicate = predicate.And(n => n.UnderlyingInstrumentType != ConsGlobal.InstrumentType.CommodityFutures || n.MaturityDate >= req.MinMaturityDate.Value);
|
||||
}
|
||||
else if (!req.IncludeMatured)
|
||||
{
|
||||
var valueDate = valuedateBLL.ValueDate;
|
||||
predicate = predicate.And(n => n.UnderlyingInstrumentType != ConsGlobal.InstrumentType.CommodityFutures || n.MaturityDate >= valueDate);
|
||||
}
|
||||
|
||||
//标的代码
|
||||
|
||||
var filterCode = req.FilterCode.TrimToNull();
|
||||
if (filterCode != null)
|
||||
{
|
||||
predicate = predicate.And(n => n.UnderlyingCode.StartsWith(filterCode));
|
||||
|
||||
if (filterCode.Length >= 4 && req.MaxShowLength > 10)
|
||||
{
|
||||
req.MaxShowLength = 10;
|
||||
}
|
||||
}
|
||||
else if (req.VarietyId != 0) //品种ID
|
||||
{
|
||||
predicate = predicate.And(n => n.UnderlyingTypeId == req.VarietyId);
|
||||
}
|
||||
|
||||
return predicate;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标的选择请求Model
|
||||
/// </summary>
|
||||
public class UnderlyingSelectRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 最大显示条目数(默认20)
|
||||
/// </summary>
|
||||
public int MaxShowLength { get; set; } = 20;
|
||||
|
||||
/// <summary>
|
||||
/// 客户ID(用于客户授信时配置的限制交易品种过滤)
|
||||
/// </summary>
|
||||
public int ClientId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 使用角色权限过滤(默认false)
|
||||
/// </summary>
|
||||
public bool UseRightFilter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标的资产类型
|
||||
/// </summary>
|
||||
public IEnumerable<string> InstrumentTypes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 包括组合标的(默认false)
|
||||
/// </summary>
|
||||
public bool IncludeSynthetic { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 只取组合标的(默认false)
|
||||
/// </summary>
|
||||
public bool OnlySynthetic { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 包括篮子标的(默认false)
|
||||
/// </summary>
|
||||
public bool IncludeBasket { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 只取篮子标的(默认false)
|
||||
/// </summary>
|
||||
public bool OnlyBasket { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 检查标的启用状态(默认true)
|
||||
/// </summary>
|
||||
public bool CheckLaunch { get; set; } = true;
|
||||
|
||||
//--------特殊处理------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// 使用拼音过滤
|
||||
/// </summary>
|
||||
public bool UsePinYinFilter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 包括已过期标的(默认false)()
|
||||
/// </summary>
|
||||
public bool IncludeMatured { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 代码过滤(默认null)
|
||||
/// </summary>
|
||||
public string FilterCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 品种ID(只在FilterCode为空时时所用)
|
||||
/// </summary>
|
||||
public int VarietyId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 只使用FilterCode精确匹配
|
||||
/// </summary>
|
||||
public bool ExcatCodeFilter { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 必须返回一个标的
|
||||
/// </summary>
|
||||
public bool MustRetOne { get; set; }
|
||||
|
||||
//--------数据用途------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// 用于交易
|
||||
/// </summary>
|
||||
public bool UseForTrading { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 大于0时用于区分互换还是场外
|
||||
/// </summary>
|
||||
public int BlackLimit { get; set; }
|
||||
|
||||
//--------标的ID------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// 标的ID
|
||||
/// </summary>
|
||||
public int UnderlyingId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 使用场景
|
||||
/// </summary>
|
||||
public string Scenario { get; set; }
|
||||
|
||||
//--------到期日限定------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// 最小到期日
|
||||
/// </summary>
|
||||
public DateTime? MinMaturityDate { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{FilterCode}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标的选项
|
||||
/// </summary>
|
||||
public class UnderlyingSelectItem
|
||||
{
|
||||
/// <summary>
|
||||
/// 标的ID
|
||||
/// </summary>
|
||||
public int id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标的名称
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标的代码
|
||||
/// </summary>
|
||||
public string Code { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 品种ID
|
||||
/// </summary>
|
||||
public int VarietyId { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{id}--{Name}--{Code}--{VarietyId}";
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标的选项
|
||||
/// </summary>
|
||||
public class UnderlyingSelectItem2 : UnderlyingSelectItem
|
||||
{
|
||||
/// <summary>
|
||||
/// 是否组合标的
|
||||
/// </summary>
|
||||
public bool IsSynthetic { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否属于篮子标的
|
||||
/// </summary>
|
||||
public bool IsBasket { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 资产类型
|
||||
/// </summary>
|
||||
public string InstrumentType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 到期日
|
||||
/// </summary>
|
||||
public string MaturityDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 份额和数量的乘积因子
|
||||
/// </summary>
|
||||
public int CountRatio { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 合约乘数
|
||||
/// </summary>
|
||||
public double ContractSize { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 最新价格
|
||||
/// </summary>
|
||||
public double Price { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 分红率
|
||||
/// </summary>
|
||||
public double? DividendRate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易单位
|
||||
/// </summary>
|
||||
public string QuoteUnitString { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前黑白名单模式
|
||||
/// <para>1:黑名单</para>
|
||||
/// <para>2:白名单</para>
|
||||
/// </summary>
|
||||
public int BlackWhiteState { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 允许选择
|
||||
/// </summary>
|
||||
public bool Disallow { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 涨跌停幅度
|
||||
/// </summary>
|
||||
public string UpDownLimit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 涨停价跌停价
|
||||
/// </summary>
|
||||
public double? PrevClosePrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 债券全名
|
||||
/// </summary>
|
||||
public string UnderlyingFullName { get; set; }
|
||||
/// <summary>
|
||||
/// 标的发行量(亿)
|
||||
/// </summary>
|
||||
public decimal? IssueSize { get; set; }
|
||||
/// <summary>
|
||||
/// 标的证券发行人
|
||||
/// </summary>
|
||||
public string UnderlyingIssuer { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,339 @@
|
||||
using BaseOUDAL;
|
||||
using System.Data;
|
||||
using System.Runtime.Intrinsics.Arm;
|
||||
using YLErp.Commons;
|
||||
using YLErp.DBModels;
|
||||
using YLErp.Helpers;
|
||||
using YLErp.Modules.ClientModule;
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 分红率服务
|
||||
/// </summary>
|
||||
public class UnderlyingSpanTwoService : YLBaseService
|
||||
{
|
||||
public UnderlyingSpanTwoService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取最新分红率
|
||||
/// </summary>
|
||||
public SearchListResult<UnderlyingSpanTwoDto> GetLatestList(UnderlyingSpanTwoQueryModel req)
|
||||
{
|
||||
// DbContext.SetDebugLog();
|
||||
var groupSpan = DbContext.UnderlyingSpanTwo.AsNoTracking()
|
||||
.GroupBy(s => s.UnderlyingId)
|
||||
.Select(g => new
|
||||
{
|
||||
UnderlyingId = g.Key,
|
||||
ValueDate = g.Max(s => s.ValueDate)
|
||||
});
|
||||
|
||||
var span = DbContext.UnderlyingSpanTwo.AsNoTracking().Join
|
||||
(groupSpan, s => new { f1 = s.UnderlyingId, f2 = s.ValueDate }, u => new { f1 = u.UnderlyingId, f2 = u.ValueDate },
|
||||
(s, u) => new { s, u })
|
||||
.Select(g => new
|
||||
{
|
||||
id = g.s.id,
|
||||
UnderlyingId = g.u.UnderlyingId,
|
||||
SpanRate = g.s.SpanRate,
|
||||
ValueDate = g.u.ValueDate
|
||||
});
|
||||
var query = span.AsNoTracking().Join(DbContext.underlying_manager, s => s.UnderlyingId, u => u.id, (s, u) => new UnderlyingSpanTwoDto
|
||||
{
|
||||
id = s.id,
|
||||
SpanRate = s.SpanRate,
|
||||
UnderlyingCode = u.UnderlyingCode,
|
||||
UnderlyingName = u.UnderlyingName
|
||||
});
|
||||
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(req.UnderlyingCode))
|
||||
{
|
||||
query = query.Where(n => n.UnderlyingCode.Contains(req.UnderlyingCode));
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(req.UnderlyingName))
|
||||
{
|
||||
query = query.Where(n => n.UnderlyingName.Contains(req.UnderlyingName));
|
||||
}
|
||||
|
||||
|
||||
if (string.IsNullOrEmpty(req.sidx))
|
||||
{
|
||||
query = query.OrderBy(n => n.UnderlyingCode);
|
||||
}
|
||||
|
||||
|
||||
return query.ToSearchList(req);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取最新分红率
|
||||
/// </summary>
|
||||
public List<UnderlyingSpanTwoDto> GetLatestList(List<string> underlyingCodes, DateTime valueDate)
|
||||
{
|
||||
var groupSpan =
|
||||
DbContext.UnderlyingSpanTwo.AsNoTracking()
|
||||
.Where(O => O.ValueDate <= valueDate)
|
||||
.GroupBy(s => s.UnderlyingId)
|
||||
.Select(g => new
|
||||
{
|
||||
UnderlyingId = g.Key,
|
||||
ValueDate = g.Max(s => s.ValueDate)
|
||||
});
|
||||
|
||||
var span = DbContext.UnderlyingSpanTwo.AsNoTracking().Join
|
||||
(groupSpan, s => new { f1 = s.UnderlyingId, f2 = s.ValueDate }, u => new { f1 = u.UnderlyingId, f2 = u.ValueDate },
|
||||
(s, u) => new { s, u })
|
||||
.Select(g => new
|
||||
{
|
||||
id = g.s.id,
|
||||
UnderlyingId = g.u.UnderlyingId,
|
||||
SpanRate = g.s.SpanRate,
|
||||
ValueDate = g.u.ValueDate
|
||||
});
|
||||
var query = span.AsNoTracking().Join(DbContext.underlying_manager, s => s.UnderlyingId, u => u.id, (s, u) => new UnderlyingSpanTwoDto
|
||||
{
|
||||
id = s.id,
|
||||
SpanRate = s.SpanRate,
|
||||
UnderlyingCode = u.UnderlyingCode,
|
||||
UnderlyingName = u.UnderlyingName
|
||||
});
|
||||
|
||||
|
||||
if (underlyingCodes?.Count() > 0)
|
||||
{
|
||||
query = query.Where(n => underlyingCodes.Contains(n.UnderlyingCode));
|
||||
}
|
||||
|
||||
return query.ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取历史分红率
|
||||
/// </summary>
|
||||
public IEnumerable<UnderlyingSpanTwoDto> GetHisList(string underlyingCode)
|
||||
{
|
||||
if (string.IsNullOrEmpty(underlyingCode))
|
||||
{
|
||||
return Enumerable.Empty<UnderlyingSpanTwoDto>();
|
||||
}
|
||||
|
||||
var query = from m in DbContext.underlying_manager
|
||||
join n in DbContext.UnderlyingSpanTwo on m.id equals n.UnderlyingId
|
||||
where m.UnderlyingCode == underlyingCode
|
||||
orderby n.ValueDate descending
|
||||
select new UnderlyingSpanTwoDto
|
||||
{
|
||||
SpanRate = n.SpanRate,
|
||||
ValueDate = n.ValueDate
|
||||
};
|
||||
return query.ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取最新分红率
|
||||
/// </summary>
|
||||
public UnderlyingSpanTwoDto GetLatestDetail(string underlyingCode)
|
||||
{
|
||||
var span = DbContext.UnderlyingSpanTwo.AsNoTracking().Join
|
||||
(DbContext.underlying_manager, s => s.UnderlyingId, u => u.id, (s, u) => new UnderlyingSpanTwoDto
|
||||
{
|
||||
UnderlyingCode = u.UnderlyingCode,
|
||||
UnderlyingName = u.UnderlyingName,
|
||||
SpanRate = s.SpanRate,
|
||||
ValueDate = s.ValueDate
|
||||
}).Where(s => s.UnderlyingCode == underlyingCode).OrderByDescending(x => x.ValueDate).FirstOrDefault();
|
||||
|
||||
if (span == null)
|
||||
{
|
||||
var variety = DataCacheProvider.GetVariety(underlyingCode);
|
||||
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode);
|
||||
|
||||
if (um != null && variety != null && !variety.UpLimit.IsNullOrWhiteSpace())
|
||||
{
|
||||
span = new UnderlyingSpanTwoDto
|
||||
{
|
||||
UnderlyingCode = underlyingCode,
|
||||
UnderlyingName = um.UnderlyingName,
|
||||
SpanRate = variety.UpLimitValue
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return span;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存分红率
|
||||
/// </summary>
|
||||
public UnderlyingSpanTwo SaveData(UnderlyingSpanTwoDto model)
|
||||
{
|
||||
if (string.IsNullOrEmpty(model?.UnderlyingCode))
|
||||
{
|
||||
throw new ServiceException("标的代码不能为空");
|
||||
}
|
||||
|
||||
var udm = DbContext.underlying_manager.FirstOrDefault(n => n.UnderlyingCode == model.UnderlyingCode);
|
||||
if (udm == null)
|
||||
{
|
||||
throw new ServiceException("标的信息不存在");
|
||||
}
|
||||
|
||||
var valueDate = BLL.valuedateBLL.ValueDate;
|
||||
if (valueDate < DateTime.Today) valueDate = DateTime.Today;
|
||||
|
||||
var span = DbContext.UnderlyingSpanTwo.FirstOrDefault(n => n.UnderlyingId == udm.id && n.ValueDate == valueDate);
|
||||
|
||||
AddOrSaveSpanTwo(span, udm.id, valueDate, model.SpanRate);
|
||||
|
||||
return span;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 导入Span涨幅度2
|
||||
/// </summary>
|
||||
/// <param name="streamIn"></param>
|
||||
/// <param name="totalNum">当前文件中的目标期权总条数</param>
|
||||
/// <param name="successNum">成功入库的数量</param>
|
||||
public void ImportSpanTwoFromExcel(Stream streamIn, out int totalNum, out int successNum)
|
||||
{
|
||||
totalNum = 0;
|
||||
successNum = 0;
|
||||
|
||||
var rowIndex = 0;
|
||||
try
|
||||
{
|
||||
var ds = Office.ExcelHelper.ReadExcelAsDataSet(streamIn, new[] { 0 }, 0);
|
||||
|
||||
if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 2)
|
||||
{
|
||||
throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" };
|
||||
}
|
||||
|
||||
var table = ds.Tables[0];
|
||||
var reader = new DataRowReader(table, 0);
|
||||
|
||||
rowIndex = 1;
|
||||
totalNum = table.Rows.Count - rowIndex;
|
||||
|
||||
//using (var trans = BeginTransaction())
|
||||
//{
|
||||
foreach (var row in table.Rows.Cast<DataRow>().Skip(1))
|
||||
{
|
||||
rowIndex++;
|
||||
|
||||
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
|
||||
{
|
||||
totalNum--;
|
||||
continue;
|
||||
}
|
||||
|
||||
reader.SetDataRow(row);
|
||||
|
||||
var underlyingCode = reader.GetString("标的代码", true);
|
||||
|
||||
|
||||
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode);
|
||||
if (um == null)
|
||||
{
|
||||
throw new ServiceException("该标的代码在系统中不存在");
|
||||
}
|
||||
|
||||
var valueDate = reader.GetDate("变动日期", false);
|
||||
var spanRate = reader.GetPercent("Span涨跌幅度2", false);
|
||||
|
||||
if (valueDate == null) valueDate = DateTime.Today;
|
||||
if (spanRate == null) continue;
|
||||
|
||||
if(spanRate < 0) throw new ServiceException("只能填大于等于0的数字");
|
||||
|
||||
var span = DbContext.UnderlyingSpanTwo.FirstOrDefault(n => n.UnderlyingId == um.id && n.ValueDate == valueDate);
|
||||
AddOrSaveSpanTwo(span, um.id, (DateTime)valueDate, spanRate);
|
||||
|
||||
successNum++;
|
||||
}
|
||||
|
||||
//trans.Commit();
|
||||
//}
|
||||
}
|
||||
catch (ServiceException se)
|
||||
{
|
||||
if (se.Tag != null)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
throw new ServiceException($"第{rowIndex}行,{se.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger("导入Span涨跌幅2").Error(ex);
|
||||
throw new ServiceException($"第{rowIndex}行,发生错误:{ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存Span涨跌幅2
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
/// <param name="valueDate"></param>
|
||||
/// <param name="spanRate"></param>
|
||||
private void AddOrSaveSpanTwo(UnderlyingSpanTwo span, int id, DateTime valueDate, double? spanRate)
|
||||
{
|
||||
|
||||
if (span == null)
|
||||
{
|
||||
span = new UnderlyingSpanTwo
|
||||
{
|
||||
UnderlyingId = id,
|
||||
ValueDate = valueDate
|
||||
};
|
||||
DbContext.UnderlyingSpanTwo.Add(span);
|
||||
}
|
||||
|
||||
var remark = $"从{span.SpanRate}修改为";
|
||||
|
||||
if(spanRate < 0)
|
||||
{
|
||||
throw new ServiceException("Span涨跌幅2必须大于等于0");
|
||||
}
|
||||
span.SpanRate = spanRate;
|
||||
span.OptId = UserId;
|
||||
span.OptName = UserName;
|
||||
span.OptDate = DateTime.Now;
|
||||
|
||||
remark = $"{span.OptDate}" + remark + $"{spanRate}";
|
||||
|
||||
|
||||
var spanLog = new Processlog()
|
||||
{
|
||||
TypeId = span.UnderlyingId,
|
||||
ProcessType = "Span2Setting",
|
||||
ProcessStatus = "保存",
|
||||
Log = "",
|
||||
Remark = remark,
|
||||
OptId = UserId,
|
||||
CreateTime = DateTime.Now
|
||||
};
|
||||
DbContext.CreditProcessLog.Add(spanLog);
|
||||
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class UnderlyingSpanTwoQueryModel : BaseSearchReq
|
||||
{
|
||||
public string UnderlyingName { get; set; }
|
||||
|
||||
public string UnderlyingCode { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using YLErp.BLL;
|
||||
using YLErp.Modules.DataProviderModule;
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 标的价格服务
|
||||
/// </summary>
|
||||
public class UnderlyingSpotPriceService : YLBaseService
|
||||
{
|
||||
public UnderlyingSpotPriceService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取标的价格
|
||||
/// </summary>
|
||||
public UnderlyingSpotPriceResult GetSpotPrice(UnderlyingSpotPriceRequest req)
|
||||
{
|
||||
if (req is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(req));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(req.UnderlyingCode))
|
||||
{
|
||||
throw new ServiceException("缺少标的代码");
|
||||
}
|
||||
|
||||
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(req.UnderlyingCode);
|
||||
|
||||
if (um == null)
|
||||
{
|
||||
throw new ServiceException("标的信息未找到:" + req.UnderlyingCode);
|
||||
}
|
||||
|
||||
var price = um.Price;
|
||||
|
||||
SyntheticPriceModel synthetic = null;
|
||||
|
||||
if (um.CommodityCode == "组合标的")
|
||||
{
|
||||
using var syntheService = new SyntheticUnderlyingPriceService(OptUser);
|
||||
synthetic = req.ValueDate != null && req.ValueDate != DateTime.MinValue
|
||||
? syntheService.GetPriceModel(req.UnderlyingCode, req.ValueDate.Value)
|
||||
: syntheService.GetPriceModel(req.UnderlyingCode);
|
||||
synthetic ??= new SyntheticPriceModel();
|
||||
}
|
||||
else if (req.ValueDate != null && req.ValueDate != valuedateBLL.ValueDate
|
||||
&& EodPriceQueryService.TryGetEodPrice(req.ValueDate.Value, req.UnderlyingCode, out var eodPrice))
|
||||
{
|
||||
price = eodPrice.ClosePrice;
|
||||
}
|
||||
|
||||
return new UnderlyingSpotPriceResult { SpotPrice = synthetic?.Price ?? price, Synthetic = synthetic };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 标的价格请求
|
||||
/// </summary>
|
||||
public class UnderlyingSpotPriceRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// 标的代码
|
||||
/// </summary>
|
||||
public string UnderlyingCode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 取值日期
|
||||
/// </summary>
|
||||
public DateTime? ValueDate { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 定价页面期初标的价格
|
||||
/// </summary>
|
||||
public class UnderlyingSpotPriceResult
|
||||
{
|
||||
/// <summary>
|
||||
/// 标的价格
|
||||
/// </summary>
|
||||
public double? SpotPrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 组合标的价格信息
|
||||
/// </summary>
|
||||
public SyntheticPriceModel Synthetic { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
using BaseOUDAL;
|
||||
using YLErp.Model;
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 基差曲线管理
|
||||
/// </summary>
|
||||
public class Underlying_BasisCurveService : YLBaseService
|
||||
{
|
||||
public Underlying_BasisCurveService(YLBaseService baseService) : base(baseService)
|
||||
{
|
||||
}
|
||||
public Underlying_BasisCurveService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
|
||||
}
|
||||
public Underlying_BasiscurveDot GetUnderlying_BasisCurve(int enid)
|
||||
{
|
||||
var query = from u in DbContext.underlying_basis_curve.AsEnumerable()
|
||||
where u.id == enid
|
||||
select new Underlying_BasiscurveDot
|
||||
{
|
||||
id = u.id,
|
||||
//VarietyId = UnderlyingDataProvider.GetUnderlying(u.UnderlyingCode)?.UnderlyingTypeId ?? 0,
|
||||
UnderlyingId = u.UnderlyingId,
|
||||
UnderlyingCode = u.UnderlyingCode,
|
||||
InterpolationMethod = u.InterpolationMethod,
|
||||
InterpolationData = JsonHelper.Deserialize<List<Underlying_BasiscurveList>>(u.InterpolationData)
|
||||
};
|
||||
var res = query.FirstOrDefault();
|
||||
res.VarietyId = UnderlyingDataProvider.GetUnderlying(res.UnderlyingCode)?.UnderlyingTypeId ?? 0;
|
||||
return res;
|
||||
}
|
||||
/// <summary>
|
||||
/// 查询基差曲线列表
|
||||
/// </summary>
|
||||
/// <param name="req"></param>
|
||||
/// <returns></returns>
|
||||
public SearchListResult<Underlying_basisCurveLinq> SearchList(Underlying_basiscurveReq req)
|
||||
{
|
||||
var query = from source in DbContext.underlying_basis_curve
|
||||
join un in DbContext.underlying_manager on source.UnderlyingCode equals un.UnderlyingCode
|
||||
select new Underlying_basisCurveLinq
|
||||
{
|
||||
id = source.id,
|
||||
UnderlyingTypeId = un.UnderlyingTypeId,
|
||||
UnderlyingCode = source.UnderlyingCode,
|
||||
UnderlyingName = un.UnderlyingName,
|
||||
OptName = source.OptName,
|
||||
OptData = source.OptDate,
|
||||
};
|
||||
if (!string.IsNullOrEmpty(req.UnderlyingCode))
|
||||
{
|
||||
query = query.Where(d => d.UnderlyingCode.Contains(req.UnderlyingCode));
|
||||
}
|
||||
if (req.UnderlyingTypeId != null)
|
||||
{
|
||||
query = query.Where(d => req.UnderlyingTypeId.Contains(d.UnderlyingTypeId));
|
||||
}
|
||||
if (string.IsNullOrEmpty(req.sidx))
|
||||
{
|
||||
req.sidx = "id";
|
||||
req.sord = "asc";
|
||||
}
|
||||
SearchListResult<Underlying_basisCurveLinq> retListResult = query.ToSearchList(req);
|
||||
return retListResult;
|
||||
}
|
||||
public void SaveUnderlying_Basiscurve(Underlying_BasiscurveDot model)
|
||||
{
|
||||
if (model is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(model));
|
||||
}
|
||||
if (model.InterpolationData == null || !model.InterpolationData.Any())
|
||||
{
|
||||
throw new ServiceException("基差曲线列表没有任何数据");
|
||||
}
|
||||
if (model.InterpolationData.Any(n => string.IsNullOrWhiteSpace(n.UnderlyingCodes)))
|
||||
{
|
||||
throw new ServiceException("基差曲线列表配置错误");
|
||||
}
|
||||
if (DbContext.underlying_basis_curve.Any(c => c.UnderlyingCode == model.UnderlyingCode))
|
||||
{
|
||||
throw new ServiceException("基差曲线列表已经存在该标的");
|
||||
}
|
||||
underlying_basis_curve underlying_Basis_Curve = null;
|
||||
underlying_Basis_Curve = new underlying_basis_curve
|
||||
{
|
||||
InterpolationMethod = model.InterpolationMethod,
|
||||
UnderlyingId = model.UnderlyingId,
|
||||
UnderlyingCode = model.UnderlyingCode,
|
||||
InterpolationData = JsonHelper.Stringify(model.InterpolationData),
|
||||
OptId = UserId,
|
||||
OptName = UserName,
|
||||
OptDate = DateTime.Now
|
||||
};
|
||||
DbContext.underlying_basis_curve.Add(underlying_Basis_Curve);
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
public Underlying_BasiscurveDot GetBasketUnderlying_Basiscurve(int id)
|
||||
{
|
||||
|
||||
var query = from u in DbContext.underlying_basis_curve.AsEnumerable()
|
||||
where u.id == id
|
||||
select new Underlying_BasiscurveDot
|
||||
{
|
||||
UnderlyingCode = u.UnderlyingCode,
|
||||
InterpolationMethod = u.InterpolationMethod,
|
||||
InterpolationData = JsonHelper.Deserialize<List<Underlying_BasiscurveList>>(u.InterpolationData)
|
||||
};
|
||||
var res = query.FirstOrDefault();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,367 @@
|
||||
using BaseOUDAL;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text.RegularExpressions;
|
||||
using YLErp.Model;
|
||||
using YLErp.Modules;
|
||||
using YLErp.Modules.DicForTranslationModule;
|
||||
using YLErp.Modules.UnderlyingModule;
|
||||
|
||||
namespace YLErp.BLL
|
||||
{
|
||||
public class underlying_managerBLL
|
||||
{
|
||||
private readonly YLContext db = new YLContext();
|
||||
|
||||
public static IQueryable<underlying_manager> GetQuery()
|
||||
{
|
||||
return new YLContext().underlying_manager.AsNoTracking();
|
||||
}
|
||||
|
||||
public static underlying_manager GetById(int id)
|
||||
{
|
||||
return DataCacheProvider.GetUnderlyingDataSource().GetData(id);
|
||||
}
|
||||
|
||||
public static underlying_manager GetByCode(string underlyingCode)
|
||||
{
|
||||
return DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取标的涨停幅度(OTC-8856重构)
|
||||
/// </summary>
|
||||
public static double GetUpLimit(string underlyingCode)
|
||||
{
|
||||
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode);
|
||||
return underlying == null ? 0 : DataCacheProvider.GetVarietyDataSource().GetData(underlying.UnderlyingTypeId)?.UpLimitValue ?? 0;
|
||||
}
|
||||
|
||||
public static List<underlying_manager> GetUnderlyingManagerByVarieties(List<Variety> varieties)
|
||||
{
|
||||
if (varieties == null || varieties.Count == 0)
|
||||
{
|
||||
return new List<underlying_manager>();
|
||||
}
|
||||
|
||||
var varietyIds = varieties.Select(x => x.id).ToList();
|
||||
return GetQuery().Where(x => varietyIds.Contains(x.UnderlyingTypeId)).ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 是否有色金属(特定情况下可以使用汉语拼音)
|
||||
/// </summary>
|
||||
public static bool IsYouSeJinShu(string underlyingcode)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(underlyingcode))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
underlyingcode = underlyingcode.TrimStart();
|
||||
if (underlyingcode.Length < 2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var arr = new[] { "AL", "CU", "ZN", "NI" };
|
||||
return arr.Contains(underlyingcode.Substring(0, 2).ToUpperInvariant());
|
||||
}
|
||||
|
||||
public static List<underlying_manager> GetAllLiveunderlying_managerModel()
|
||||
{
|
||||
return GetQuery().Where(u => u.UnderlyingState != "Matured" && u.LaunchState == "1").ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static void MergeUnderlyingFromTrade(underlying_manager underlying, OtcTradeBase trade)
|
||||
{
|
||||
//临时设置underlying
|
||||
underlying.id = trade.UnderlyingId;
|
||||
underlying.UnderlyingCode = trade.UnderlyingCode;
|
||||
underlying.UnderlyingInstrumentType = trade.UnderlyingInstrumentType;
|
||||
underlying.Price = trade.SpotPrice;
|
||||
if (underlying.QuotationDate == null)
|
||||
{
|
||||
underlying.QuotationDate = trade.TradeDate;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取某个underlying的最新价格
|
||||
/// </summary>
|
||||
public static double GetUnderlyingPrice(int id)
|
||||
{
|
||||
using (var db = new YLContext())
|
||||
{
|
||||
var um = db.underlying_manager.Where(x => x.id == id)
|
||||
.Select(n => new { n.Price, n.CommodityCode, n.UnderlyingCode }).FirstOrDefault();
|
||||
|
||||
if (um == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (um.CommodityCode == "组合标的")
|
||||
{
|
||||
return new SyntheticUnderlyingPriceService(OptUserInfo.SystemUser).GetPrice(um.UnderlyingCode) ?? 0;
|
||||
}
|
||||
|
||||
return um.Price ?? 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取所有股票标的
|
||||
/// </summary>
|
||||
public static List<underlying_manager> GetAllStockModel()
|
||||
{
|
||||
return GetQuery().Where(u => u.UnderlyingInstrumentType == "Stock").ToList();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 如:rb1893 获取为RB,规则获取最初的非数字头
|
||||
/// </summary>
|
||||
public static string GetCommodityCodeByUnCode(string underlyingCode)
|
||||
{
|
||||
var re = new Regex("^[a-zA-Z]");
|
||||
return re.Match(underlyingCode).Groups[0].Value;
|
||||
}
|
||||
|
||||
public underlying_manager UpdateSingle(int id, UnderlyingManagerReq data)
|
||||
{
|
||||
var model = db.underlying_manager.Find(id);
|
||||
Setunderlying_manager(model, data);
|
||||
db.SaveChanges();
|
||||
return model;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置model,如果不为空就设置,如果为空则和之前一样
|
||||
/// </summary>
|
||||
public underlying_manager Setunderlying_manager(underlying_manager model, UnderlyingManagerReq data)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(data.LaunchState))
|
||||
{
|
||||
model.LaunchState = data.LaunchState;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(data.MarketName))
|
||||
{
|
||||
model.MarketName = data.MarketName;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(data.UnderlyingName))
|
||||
{
|
||||
model.UnderlyingName = data.UnderlyingName;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(data.UnderlyingCode))
|
||||
{
|
||||
model.UnderlyingCode = data.UnderlyingCode;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(data.UnderlyingType))
|
||||
{
|
||||
model.UnderlyingType = data.UnderlyingType;
|
||||
}
|
||||
|
||||
if (data.MaturityDate != null && data.MaturityDate != DateTime.MinValue)
|
||||
{
|
||||
model.MaturityDate = data.MaturityDate.Value;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(data.UnderlyingState))
|
||||
{
|
||||
model.UnderlyingState = data.UnderlyingState;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(data.Desc))
|
||||
{
|
||||
model.UnderlyingDesc = data.Desc;
|
||||
}
|
||||
|
||||
if (data.OptId != null)
|
||||
{
|
||||
model.OptId = data.OptId.Value;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(data.OptName))
|
||||
{
|
||||
model.OptName = data.OptName;
|
||||
}
|
||||
|
||||
if (data.OptDate != null && data.OptDate != DateTime.MinValue)
|
||||
{
|
||||
model.OptDate = data.OptDate.Value;
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询underlying_manager
|
||||
/// </summary>
|
||||
public SearchListResult<underlying_manager> SearchList(UnderlyingManagerReq req, IEnumerable<int> vars = null)
|
||||
{
|
||||
var predicate = BuildPredicate(req, vars);
|
||||
var predicate2 = PredicateBuilder.True<Variety>();
|
||||
if (req.VarietyCodeList != null)
|
||||
{
|
||||
predicate2 = predicate2.And(d => req.VarietyCodeList.Contains(d.VarietyCode));
|
||||
}
|
||||
|
||||
var query = from source in db.underlying_manager.AsNoTracking().Where(predicate)
|
||||
join vari in db.variety.Where(predicate2) on source.UnderlyingTypeId equals vari.id into varies
|
||||
from vari in varies.DefaultIfEmpty()
|
||||
select source;
|
||||
|
||||
//只正对资产码排序
|
||||
//if (req.sidx == "UnderlyingCode")
|
||||
//{
|
||||
// query = req.sord == "desc"
|
||||
// ? query.OrderByDescending(n => n.UnderlyingCode)
|
||||
// : query.OrderBy(n => n.UnderlyingCode);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// query = query.OrderByDescending(n => n.id);
|
||||
//}
|
||||
var result = query.ToSearchList(req, true);
|
||||
foreach (var um in result.rows)
|
||||
{
|
||||
new DicForTranslationService(OptUserInfo.SystemUser).GetTransWord(um);
|
||||
if (um.CommodityCode == "篮子标的")
|
||||
{
|
||||
double price = 0;
|
||||
DataCacheProvider.GetUnderlyingDataSource().TryGetPrice(um.UnderlyingCode, out price);
|
||||
um.Price = (double?)Convert.ToDecimal(price.ToString("0.000"));
|
||||
}
|
||||
um.Price = um.CommodityCode == "组合标的" ? new SyntheticUnderlyingPriceService(OptUserInfo.SystemUser).GetPrice(um.UnderlyingCode) : (um.Price ?? 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static Expression<Func<underlying_manager, bool>> BuildPredicate(UnderlyingManagerReq req, IEnumerable<int> vars)
|
||||
{
|
||||
var predicate = PredicateBuilder.True<underlying_manager>();
|
||||
|
||||
if (vars != null)
|
||||
{
|
||||
predicate = predicate.And(d => vars.Contains(d.UnderlyingTypeId));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.UnderlyingTypeId))
|
||||
{
|
||||
var typeids = req.UnderlyingTypeId.Split(',').Select(s => Convert.ToInt32(s)).ToList();
|
||||
predicate = predicate.And(d => typeids.Contains(d.UnderlyingTypeId)); ;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.MarketCode))
|
||||
{
|
||||
predicate = predicate.And(d => d.MarketCode == req.MarketCode);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.MarketName))
|
||||
{
|
||||
predicate = predicate.And(d => d.MarketName.Contains(req.MarketName));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.UnderlyingName))
|
||||
{
|
||||
predicate = predicate.And(d => d.UnderlyingName.Contains(req.UnderlyingName));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.UnderlyingCode))
|
||||
{
|
||||
predicate = predicate.And(d => d.UnderlyingCode.Contains(req.UnderlyingCode));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.UnderlyingType))
|
||||
{
|
||||
var underlyingTypes = req.UnderlyingType.Split(',');
|
||||
predicate = predicate.And(d => underlyingTypes.Contains(d.UnderlyingType));
|
||||
}
|
||||
if (req.MaturityDateStart != DateTime.MinValue)
|
||||
{
|
||||
predicate = predicate.And(d => d.MaturityDate >= req.MaturityDateStart);
|
||||
}
|
||||
|
||||
if (req.MaturityDateEnd != DateTime.MinValue)
|
||||
{
|
||||
var MaturityDateTemp = req.MaturityDateEnd.AddDays(1);
|
||||
predicate = predicate.And(d => d.MaturityDate < MaturityDateTemp);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(req.UnderlyingState))
|
||||
{
|
||||
predicate = predicate.And(d => d.UnderlyingState.Contains(req.UnderlyingState));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.UnderlyingStatus))
|
||||
{
|
||||
predicate = predicate.And(d => req.UnderlyingStatus == d.UnderlyingStatus);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.Desc))
|
||||
{
|
||||
predicate = predicate.And(d => d.UnderlyingDesc.Contains(req.Desc));
|
||||
}
|
||||
|
||||
if (req.OptId != null)
|
||||
{
|
||||
predicate = predicate.And(d => d.OptId == req.OptId);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.OptName))
|
||||
{
|
||||
predicate = predicate.And(d => d.OptName.Contains(req.OptName));
|
||||
}
|
||||
|
||||
if (req.OptDateStart != DateTime.MinValue)
|
||||
{
|
||||
predicate = predicate.And(d => d.OptDate >= req.OptDateStart);
|
||||
}
|
||||
|
||||
if (req.OptDateEnd != DateTime.MinValue)
|
||||
{
|
||||
var OptDateTemp = req.OptDateEnd.AddDays(1);
|
||||
predicate = predicate.And(d => d.OptDate < OptDateTemp);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.LaunchState))
|
||||
{
|
||||
//0未启用,不是1
|
||||
if (req.LaunchState == "0")
|
||||
{
|
||||
predicate = predicate.And(d => d.LaunchState != "1");
|
||||
}
|
||||
else
|
||||
{
|
||||
predicate = predicate.And(d => d.LaunchState == req.LaunchState);
|
||||
}
|
||||
}
|
||||
if (req.MarketNameList != null)
|
||||
{
|
||||
predicate = predicate.And(d => req.MarketNameList.Contains(d.MarketName));
|
||||
}
|
||||
if (req.MarketCodeList != null)
|
||||
{
|
||||
predicate = predicate.And(d => req.MarketCodeList.Contains(d.MarketCode));
|
||||
}
|
||||
if (req.UnderlyingCodeList != null)
|
||||
{
|
||||
predicate = predicate.And(d => req.UnderlyingCodeList.Contains(d.UnderlyingCode));
|
||||
}
|
||||
if (req.UnderlyingTypeList != null)
|
||||
{
|
||||
predicate = predicate.And(d => req.UnderlyingTypeList.Contains(d.UnderlyingType));
|
||||
}
|
||||
if (req.UnderlyingStateList != null)
|
||||
{
|
||||
predicate = predicate.And(d => req.UnderlyingStateList.Contains(d.UnderlyingState));
|
||||
}
|
||||
|
||||
return predicate;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
using BaseOUDAL;
|
||||
using YLErp.Model;
|
||||
using YLErp.Modules;
|
||||
|
||||
namespace YLErp.BLL
|
||||
{
|
||||
public class VarietyBLL
|
||||
{
|
||||
private readonly YLContext db = new YLContext();
|
||||
|
||||
public static IQueryable<Variety> GetAllvarietyModel()
|
||||
{
|
||||
return Modules.DataCacheModule.DataCacheManager.GetVarietyDataSource().AsQueryable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询variety
|
||||
/// </summary>
|
||||
public SearchListResult<Variety> SearchList(VarietyReq req)
|
||||
{
|
||||
var query = from source in db.variety select source;
|
||||
if (!string.IsNullOrEmpty(req.VarietyCode))
|
||||
{
|
||||
query = query.Where(d => d.VarietyCode.Contains(req.VarietyCode));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.VarietyName))
|
||||
{
|
||||
query = query.Where(d => d.VarietyName.Contains(req.VarietyName));
|
||||
}
|
||||
|
||||
if (req.OptId != null)
|
||||
{
|
||||
query = query.Where(d => d.OptId == req.OptId);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.OptName))
|
||||
{
|
||||
query = query.Where(d => d.OptName.Contains(req.OptName));
|
||||
}
|
||||
|
||||
if (req.OptDateStart != DateTime.MinValue)
|
||||
{
|
||||
query = query.Where(d => d.OptDate >= req.OptDateStart);
|
||||
}
|
||||
|
||||
if (req.OptDateEnd != DateTime.MinValue)
|
||||
{
|
||||
DateTime OptDateTemp = req.OptDateEnd.AddDays(1);
|
||||
query = query.Where(d => d.OptDate < OptDateTemp);
|
||||
}
|
||||
if (req.TradingMarketId != null)
|
||||
{
|
||||
query = query.Where(d => d.TradingMarketId == req.TradingMarketId);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.AssetType))
|
||||
{
|
||||
query = query.Where(d => d.AssetType.Contains(req.AssetType));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.TradingMarket))
|
||||
{
|
||||
query = query.Where(d => d.TradingMarket.Contains(req.TradingMarket));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.TradeUnit))
|
||||
{
|
||||
query = query.Where(d => d.TradeUnit.Contains(req.TradeUnit));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.QuoteUnit))
|
||||
{
|
||||
query = query.Where(d => d.QuoteUnit.Contains(req.QuoteUnit));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.MinPriceChange))
|
||||
{
|
||||
query = query.Where(d => d.MinPriceChange.Contains(req.MinPriceChange));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.UpLimit))
|
||||
{
|
||||
query = query.Where(d => d.UpLimit.Contains(req.UpLimit));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.DownLimit))
|
||||
{
|
||||
query = query.Where(d => d.DownLimit.Contains(req.DownLimit));
|
||||
}
|
||||
|
||||
if (req.Margin != null)
|
||||
{
|
||||
query = query.Where(d => d.Margin == req.Margin);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.Description))
|
||||
{
|
||||
query = query.Where(d => d.Description.Contains(req.Description));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.ContractMonth))
|
||||
{
|
||||
query = query.Where(d => d.ContractMonth.Contains(req.ContractMonth));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.TradeTimeSlot))
|
||||
{
|
||||
query = query.Where(d => d.TradeTimeSlot.Contains(req.TradeTimeSlot));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.DeliveryType))
|
||||
{
|
||||
query = query.Where(d => d.DeliveryType.Contains(req.DeliveryType));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.DeliveryPlace))
|
||||
{
|
||||
query = query.Where(d => d.DeliveryPlace.Contains(req.DeliveryPlace));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.DeliveryGrade))
|
||||
{
|
||||
query = query.Where(d => d.DeliveryGrade.Contains(req.DeliveryGrade));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.MiniDeliveryUnit))
|
||||
{
|
||||
query = query.Where(d => d.MiniDeliveryUnit.Contains(req.MiniDeliveryUnit));
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(req.sidx))
|
||||
{
|
||||
req.sidx = "id";
|
||||
req.sord = "desc";
|
||||
}
|
||||
|
||||
var sList = query.ToSearchList(req);
|
||||
|
||||
var Market = DataCacheProvider.GetMarketDataSource().AsQueryable();
|
||||
foreach (var item in sList.rows)
|
||||
{
|
||||
var market = Market?.FirstOrDefault(o => o.MarketName == item.TradingMarket);
|
||||
item.TradingMarketNo = market?.ExchangeNo;
|
||||
}
|
||||
|
||||
return sList;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,501 @@
|
||||
using System.Data;
|
||||
using YieldChain.Helpers;
|
||||
using YLErp.BLL;
|
||||
using YLErp.Commons;
|
||||
using YLErp.Models;
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 标的品种数据操作服务
|
||||
/// </summary>
|
||||
public class VarietyDalService : YLBaseService
|
||||
{
|
||||
public VarietyDalService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public void ImportExcel(Stream streamIn, out int totalNum, out int successNum)
|
||||
{
|
||||
totalNum = 0;
|
||||
successNum = 0;
|
||||
|
||||
int rowIndex = 0;
|
||||
try
|
||||
{
|
||||
var ds = Office.ExcelHelper.ReadExcelAsDataSet(streamIn, new[] { 0 }, 1);
|
||||
|
||||
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);
|
||||
|
||||
totalNum = table.Rows.Count - rowIndex;
|
||||
|
||||
foreach (var row in table.Rows.Cast<DataRow>())
|
||||
{
|
||||
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
|
||||
{
|
||||
totalNum--;
|
||||
continue;
|
||||
}
|
||||
|
||||
reader.SetDataRow(row);
|
||||
//映射导入数据
|
||||
var variety = MapVariety(reader, row);
|
||||
|
||||
//保存数据
|
||||
SaveData(variety);
|
||||
successNum++;
|
||||
rowIndex++;
|
||||
}
|
||||
}
|
||||
catch (ServiceException se)
|
||||
{
|
||||
if (se.Tag != null) throw;
|
||||
throw new ServiceException($"第{rowIndex + 2}行,发生错误:{se.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private Variety MapVariety(DataRowReader reader, DataRow row)
|
||||
{
|
||||
var variety = new Variety();
|
||||
var VarietyCode = reader.GetString("品种代码", true);
|
||||
variety.VarietyCode = VarietyCode;
|
||||
|
||||
bool isnull = VarietyCode != "篮子标的" && VarietyCode != "组合标的";
|
||||
bool isadd = true;
|
||||
if (DbContext.variety.FirstOrDefault(o => o.VarietyCode == variety.VarietyCode) != null)
|
||||
{
|
||||
variety = DbContext.variety.FirstOrDefault(o => o.VarietyCode == variety.VarietyCode);
|
||||
isadd = false;
|
||||
}
|
||||
|
||||
string marketCode = null;
|
||||
string mainCategoryCn = null;
|
||||
string contractSize = null;
|
||||
string unit = null;
|
||||
string VarietyName = null;
|
||||
string AssetType = null;
|
||||
string VarietyEnName = null;
|
||||
string EnUnit = null;
|
||||
string BBGTicker = null;
|
||||
string CommissionType = null;
|
||||
string TradedOptionCommissionType = null;
|
||||
string CloseTodayCommissionType = null;
|
||||
string commissionExchange = null;
|
||||
string commissionDeviation = null;
|
||||
string tradedOptionCommissionExchange = null;
|
||||
string tradedOptionCommissionDeviation = null;
|
||||
string closeTodayCommissionExchange = null;
|
||||
string closeTodayCommissionDeviation = null;
|
||||
|
||||
DataColumnCollection rowx = row.Table.Columns;
|
||||
foreach (DataColumn col in rowx)
|
||||
{
|
||||
switch (col.ColumnName)
|
||||
{
|
||||
case "交易所代码":
|
||||
marketCode = reader.GetString("交易所代码", false);
|
||||
break;
|
||||
case "主类型":
|
||||
mainCategoryCn = reader.GetString("主类型", PS.Config.Company == Configuration.CompanyEnum.中金);
|
||||
break;
|
||||
case "合约乘数":
|
||||
contractSize = reader.GetString("合约乘数", false);
|
||||
break;
|
||||
case "单位":
|
||||
unit = reader.GetString("单位", false);
|
||||
break;
|
||||
case "品种名":
|
||||
VarietyName = reader.GetString("品种名", false);
|
||||
break;
|
||||
case "品种类型":
|
||||
AssetType = reader.GetString("品种类型", false);
|
||||
break;
|
||||
case "品种英文名":
|
||||
VarietyEnName = reader.GetString("品种英文名", false);
|
||||
break;
|
||||
case "单位英文描述":
|
||||
EnUnit = reader.GetString("单位英文描述", false);
|
||||
break;
|
||||
case "BBG Ticker":
|
||||
BBGTicker = reader.GetString("BBG Ticker", false);
|
||||
break;
|
||||
case "交易所手续费类型":
|
||||
CommissionType = reader.GetString("交易所手续费类型", false);
|
||||
break;
|
||||
case "场内手续费类型":
|
||||
TradedOptionCommissionType = reader.GetString("场内手续费类型", false);
|
||||
break;
|
||||
case "平今仓手续费类型":
|
||||
CloseTodayCommissionType = reader.GetString("平今仓手续费类型", false);
|
||||
break;
|
||||
case "交易所手续费":
|
||||
commissionExchange = reader.GetString("交易所手续费", false);
|
||||
break;
|
||||
case "手续费偏离值":
|
||||
commissionDeviation = reader.GetString("手续费偏离值", false);
|
||||
break;
|
||||
case "交易所场内手续费":
|
||||
tradedOptionCommissionExchange = reader.GetString("交易所场内手续费", false);
|
||||
break;
|
||||
case "场内手续费偏离值":
|
||||
tradedOptionCommissionDeviation = reader.GetString("场内手续费偏离值", false);
|
||||
break;
|
||||
case "交易所平今仓手续费":
|
||||
closeTodayCommissionExchange = reader.GetString("交易所平今仓手续费", false);
|
||||
break;
|
||||
case "平今仓手续费偏离值":
|
||||
closeTodayCommissionDeviation = reader.GetString("平今仓手续费偏离值", false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var market = DataCacheProvider.GetMarketDataSource().AsQueryable().FirstOrDefault(o => o.ExchangeNo == marketCode);
|
||||
|
||||
if (isadd)
|
||||
{
|
||||
if (market == null && isnull)
|
||||
{
|
||||
throw new ServiceException("未找到交易所代码对应的交易所");
|
||||
}
|
||||
if (contractSize == null)
|
||||
{
|
||||
throw new ServiceException("未找到合约乘数");
|
||||
}
|
||||
if (unit == null)
|
||||
{
|
||||
throw new ServiceException("未找到单位");
|
||||
}
|
||||
if (VarietyName == null)
|
||||
{
|
||||
throw new ServiceException("未找到品种名");
|
||||
}
|
||||
if (AssetType == null && PS.Config.Company == Configuration.CompanyEnum.中金)
|
||||
{
|
||||
throw new ServiceException("未找到品种类型");
|
||||
}
|
||||
if (CommissionType == null)
|
||||
{
|
||||
throw new ServiceException("未找到交易所手续费类型");
|
||||
}
|
||||
if (TradedOptionCommissionType == null)
|
||||
{
|
||||
throw new ServiceException("未找到场内手续费类型");
|
||||
}
|
||||
if (CloseTodayCommissionType == null)
|
||||
{
|
||||
throw new ServiceException("未找到平今仓手续费类型");
|
||||
}
|
||||
}
|
||||
|
||||
variety.VarietyName = VarietyName == null ? variety.VarietyName : VarietyName;
|
||||
variety.AssetType = AssetType == null ? variety.AssetType : AssetType;
|
||||
variety.VarietyEnName = VarietyEnName == null ? variety.VarietyEnName : VarietyEnName;
|
||||
variety.TradingMarket = market == null ? variety.TradingMarket : market.MarketName;
|
||||
variety.TradingMarketId = market == null ? variety.TradingMarketId : market.id;
|
||||
if (contractSize != null && unit != null)
|
||||
{
|
||||
if (double.TryParse(contractSize, out var contractsize))
|
||||
{
|
||||
variety.TradeUnit = contractsize + unit + "/手";
|
||||
}
|
||||
}
|
||||
variety.EnUnit = EnUnit == null ? variety.EnUnit : EnUnit;
|
||||
variety.BBGTicker = BBGTicker == null ? variety.BBGTicker : BBGTicker;
|
||||
variety.QuoteUnit = unit == null ? variety.QuoteUnit : "元(人民币)/" + unit;
|
||||
if (mainCategoryCn != null)
|
||||
{
|
||||
variety.MainCategory = string.IsNullOrWhiteSpace(mainCategoryCn) ? null : ConsGlobal.MainCategory.GetFromDesc(mainCategoryCn);
|
||||
}
|
||||
variety.CommissionType = CommissionType == null ? variety.CommissionType : CommissionType;
|
||||
variety.TradedOptionCommissionType = VarietyName == null ? variety.TradedOptionCommissionType : TradedOptionCommissionType;
|
||||
variety.CloseTodayCommissionType = VarietyName == null ? variety.CloseTodayCommissionType : CloseTodayCommissionType;
|
||||
|
||||
if (commissionExchange != null)
|
||||
{
|
||||
if (double.TryParse(commissionExchange, out var CommissionExchange))
|
||||
{
|
||||
variety.CommissionExchange = CommissionExchange;
|
||||
}
|
||||
}
|
||||
if (commissionDeviation != null)
|
||||
{
|
||||
if (double.TryParse(commissionDeviation, out var CommissionDeviation))
|
||||
{
|
||||
variety.CommissionDeviation = CommissionDeviation;
|
||||
}
|
||||
}
|
||||
if (tradedOptionCommissionExchange != null)
|
||||
{
|
||||
if (double.TryParse(tradedOptionCommissionExchange, out var TradedOptionCommissionExchange))
|
||||
{
|
||||
variety.TradedOptionCommissionExchange = TradedOptionCommissionExchange;
|
||||
}
|
||||
}
|
||||
if (tradedOptionCommissionDeviation != null)
|
||||
{
|
||||
if (double.TryParse(tradedOptionCommissionDeviation, out var TradedOptionCommissionDeviation))
|
||||
{
|
||||
variety.TradedOptionCommissionDeviation = TradedOptionCommissionDeviation;
|
||||
}
|
||||
}
|
||||
if (closeTodayCommissionExchange != null)
|
||||
{
|
||||
if (double.TryParse(closeTodayCommissionExchange, out var CloseTodayCommissionExchange))
|
||||
{
|
||||
variety.CloseTodayCommissionExchange = CloseTodayCommissionExchange;
|
||||
}
|
||||
}
|
||||
if (closeTodayCommissionDeviation != null)
|
||||
{
|
||||
if (double.TryParse(closeTodayCommissionDeviation, out var CloseTodayCommissionDeviation))
|
||||
{
|
||||
variety.CloseTodayCommissionDeviation = CloseTodayCommissionDeviation;
|
||||
}
|
||||
}
|
||||
|
||||
using (var db = DbContextFactory.GetErpBaseContext())
|
||||
{
|
||||
var dicId = db.Dictionaries.FirstOrDefault(o => o.Name == "品种类型").Id;
|
||||
if (!db.DictionaryItems.Any(x => x.Name == variety.AssetType && x.DictId == dicId) && AssetType != null)
|
||||
{
|
||||
throw new ServiceException("未找到品种类型" + variety.AssetType);
|
||||
}
|
||||
}
|
||||
var currency = DbContext.currency.FirstOrDefault(o => o.CurrencyCode == variety.QuoteCurrency);
|
||||
if (currency == null && !string.IsNullOrEmpty(variety.QuoteCurrency))
|
||||
{
|
||||
throw new ServiceException("计价币种不存在,请先维护货币" + variety.QuoteCurrency);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(variety.QuoteCurrency))
|
||||
{
|
||||
if (variety.QuoteCurrency != "CNH" && variety.QuoteCurrency != "CNY")
|
||||
{
|
||||
variety.QuoteUnit = currency.CurrencyUnit + "/" + unit;
|
||||
}
|
||||
}
|
||||
return variety;
|
||||
}
|
||||
|
||||
|
||||
public VarietyDto GetDetail(int id)
|
||||
{
|
||||
Variety va = DbContext.variety.AsNoTracking().FirstOrDefault(n => n.id == id);
|
||||
if (va == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
var dto = new VarietyDto();
|
||||
ObjectHelper.MapValues(dto, va);
|
||||
dto.HisDataList = DbContext.VarietyHisData.Where(n => n.VarietyId == id).OrderBy(n => n.ValueDate)
|
||||
.Select(n => new HistoryData { Value = n.Value, ValueDate = n.ValueDate, ValueType = n.ValueType }).ToArray();
|
||||
return dto;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存数据
|
||||
/// </summary>
|
||||
public Variety SaveData(Variety reqModel)
|
||||
{
|
||||
Variety dbModel;
|
||||
|
||||
var isNew = reqModel.id == 0;
|
||||
|
||||
if (isNew)
|
||||
{
|
||||
dbModel = reqModel;
|
||||
if (DbContext.variety.Any(o => o.VarietyName == reqModel.VarietyName))
|
||||
{
|
||||
throw new ServiceException("保存失败,已存在名为" + reqModel.VarietyName + "的品种");
|
||||
}
|
||||
DbContext.variety.Add(dbModel);
|
||||
}
|
||||
else
|
||||
{
|
||||
dbModel = DbContext.variety.Find(reqModel.id);
|
||||
if (dbModel == null)
|
||||
{
|
||||
throw new ServiceException("保存失败,数据不存在");
|
||||
}
|
||||
UpdateChanges(dbModel, reqModel, "id");
|
||||
}
|
||||
|
||||
var currency = DbContext.currency.FirstOrDefault(o => o.CurrencyCode == dbModel.QuoteCurrency);
|
||||
if (currency == null && !string.IsNullOrEmpty(dbModel.QuoteCurrency))
|
||||
{
|
||||
throw new ServiceException("计价币种不存在,请先维护货币" + dbModel.QuoteCurrency);
|
||||
}
|
||||
|
||||
dbModel.VarietyCode = dbModel.VarietyCode;
|
||||
|
||||
if (dbModel.CommissionType == ConsCommissionType.Ratio && dbModel.CommissionExchange.HasValue)
|
||||
{
|
||||
dbModel.CommissionExchange = Convert.ToDouble(OtcFormatExtensions.OtcFormatValue(dbModel.CommissionExchange.Value / 10000, 8));
|
||||
}
|
||||
if (dbModel.CommissionType == ConsCommissionType.Ratio && dbModel.CommissionDeviation.HasValue)
|
||||
{
|
||||
dbModel.CommissionDeviation = Convert.ToDouble(OtcFormatExtensions.OtcFormatValue(dbModel.CommissionDeviation.Value / 10000, 8));
|
||||
}
|
||||
|
||||
if (dbModel.TradedOptionCommissionType == ConsCommissionType.Ratio && dbModel.TradedOptionCommissionExchange.HasValue)
|
||||
{
|
||||
dbModel.TradedOptionCommissionExchange = Convert.ToDouble(OtcFormatExtensions.OtcFormatValue(dbModel.TradedOptionCommissionExchange.Value / 10000, 8));
|
||||
}
|
||||
if (dbModel.TradedOptionCommissionType == ConsCommissionType.Ratio && dbModel.TradedOptionCommissionDeviation.HasValue)
|
||||
{
|
||||
dbModel.TradedOptionCommissionDeviation = Convert.ToDouble(OtcFormatExtensions.OtcFormatValue(dbModel.TradedOptionCommissionDeviation.Value / 10000, 8));
|
||||
}
|
||||
|
||||
if (dbModel.CloseTodayCommissionType == ConsCommissionType.Ratio && dbModel.CloseTodayCommissionExchange.HasValue)
|
||||
{
|
||||
dbModel.CloseTodayCommissionExchange = Convert.ToDouble(OtcFormatExtensions.OtcFormatValue(dbModel.CloseTodayCommissionExchange.Value / 10000, 8));
|
||||
}
|
||||
if (dbModel.CloseTodayCommissionType == ConsCommissionType.Ratio && dbModel.CloseTodayCommissionDeviation.HasValue)
|
||||
{
|
||||
dbModel.CloseTodayCommissionDeviation = Convert.ToDouble(OtcFormatExtensions.OtcFormatValue(dbModel.CloseTodayCommissionDeviation.Value / 10000, 8));
|
||||
}
|
||||
|
||||
if (dbModel.CommissionExchange.HasValue || dbModel.CommissionDeviation.HasValue)
|
||||
{
|
||||
dbModel.Commission = Convert.ToDouble(OtcFormatExtensions.OtcFormatValue((dbModel.CommissionExchange ?? 0) + (dbModel.CommissionDeviation ?? 0), 8));
|
||||
}
|
||||
else
|
||||
{
|
||||
dbModel.Commission = null;
|
||||
}
|
||||
if (dbModel.TradedOptionCommissionExchange.HasValue || dbModel.TradedOptionCommissionDeviation.HasValue)
|
||||
{
|
||||
dbModel.TradedOptionCommission = Convert.ToDouble(OtcFormatExtensions.OtcFormatValue((dbModel.TradedOptionCommissionExchange ?? 0) + (dbModel.TradedOptionCommissionDeviation ?? 0), 8));
|
||||
}
|
||||
else
|
||||
{
|
||||
dbModel.TradedOptionCommission = null;
|
||||
}
|
||||
if (dbModel.CloseTodayCommissionExchange.HasValue || dbModel.CloseTodayCommissionDeviation.HasValue)
|
||||
{
|
||||
dbModel.CloseTodayCommission = Convert.ToDouble(OtcFormatExtensions.OtcFormatValue((dbModel.CloseTodayCommissionExchange ?? 0) + (dbModel.CloseTodayCommissionDeviation ?? 0), 8));
|
||||
}
|
||||
else
|
||||
{
|
||||
dbModel.CloseTodayCommission = null;
|
||||
}
|
||||
|
||||
dbModel.OptId = UserId;
|
||||
dbModel.OptName = UserName;
|
||||
dbModel.OptDate = DateTime.Now;
|
||||
dbModel.DownLimit = dbModel.UpLimit;
|
||||
//1.修改underlying的单位
|
||||
var Underlyings = DbContext.underlying_manager.Where(o => o.CommodityCode == dbModel.VarietyCode);
|
||||
if (Underlyings != null)
|
||||
{
|
||||
foreach (var item in Underlyings)
|
||||
{
|
||||
item.UnderlyingType = dbModel.VarietyName;
|
||||
item.QuoteUnit = dbModel.QuoteUnitSingleOriginal;
|
||||
item.TradeUnit = dbModel.TradeUnitSingle;
|
||||
}
|
||||
}
|
||||
using (var trans = BeginTransaction())
|
||||
{
|
||||
DbContext.SaveChanges();
|
||||
UpdateHisData(reqModel, isNew);
|
||||
DbContext.SaveChanges();
|
||||
trans.Commit();
|
||||
}
|
||||
|
||||
new DicForTranslationModule.DicForTranslationService(OptUser).SetWordDictionary(dbModel);
|
||||
|
||||
return dbModel;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除数据
|
||||
/// </summary>
|
||||
public void RemoveData(int id)
|
||||
{
|
||||
if (DbContext.client_variety_config.Any(x => x.VarietyId == id))
|
||||
{
|
||||
throw new ServiceException("收费配置包含该品种信息,不能被删除");
|
||||
}
|
||||
|
||||
if (DbContext.client_variety_marginrate.Any(x => x.VarietyId == id))
|
||||
{
|
||||
throw new ServiceException("预付金维护包含该品种信息,不能被删除");
|
||||
}
|
||||
|
||||
var va = DbContext.variety.Find(id);
|
||||
|
||||
if (va == null)
|
||||
{
|
||||
throw new ServiceException("找不到品种信息");
|
||||
}
|
||||
|
||||
DbContext.variety.Remove(va);
|
||||
|
||||
var vvols = DbContext.variety_vol.Where(n => n.VarietyId == id).ToArray();
|
||||
DbContext.variety_vol.RemoveRange(vvols);
|
||||
|
||||
var vhis = DbContext.VarietyHisData.Where(n => n.VarietyId == id).ToArray();
|
||||
DbContext.VarietyHisData.RemoveRange(vhis);
|
||||
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存历史数据
|
||||
/// </summary>
|
||||
private void UpdateHisData(Variety newData, bool isNew)
|
||||
{
|
||||
var sysDate = valuedateBLL.ValueDate;
|
||||
|
||||
var newPara = MarginParamModel.Create(newData.Margin, newData.VolatilityRate, newData.UpLimit, false);
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(newData.VolatilityRate) && !newPara.VolatilityRate.HasValue)
|
||||
{
|
||||
throw new ServiceException("解析Span波动率变动失败:" + newData.VolatilityRate);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(newData.UpLimit) && !newPara.UpDownLimit.HasValue)
|
||||
{
|
||||
throw new ServiceException("解析Span涨跌幅度失败:" + newData.UpLimit);
|
||||
}
|
||||
|
||||
if (isNew)
|
||||
{
|
||||
DbContext.BulkDelete<VarietyHisData>($"{nameof(VarietyHisData.VarietyId)}='{newData.id}'");
|
||||
}
|
||||
|
||||
var hisdataService = new VarietyHisDataService(this);
|
||||
var valdate = isNew ? new DateTime(2000, 1, 1) : valuedateBLL.ValueDate;
|
||||
|
||||
hisdataService.AddOrUpdateHisData(new VarietyHisDataAddOrUpdateRequest
|
||||
{
|
||||
VarietyId = newData.id,
|
||||
ValueType = nameof(MarginParamModel.MarginRate),
|
||||
Value = newPara.MarginRate,
|
||||
ValueDate = valdate
|
||||
}, false);
|
||||
|
||||
hisdataService.AddOrUpdateHisData(new VarietyHisDataAddOrUpdateRequest
|
||||
{
|
||||
VarietyId = newData.id,
|
||||
ValueType = nameof(MarginParamModel.VolatilityRate),
|
||||
Value = newPara.VolatilityRate,
|
||||
ValueDate = valdate
|
||||
}, false);
|
||||
|
||||
hisdataService.AddOrUpdateHisData(new VarietyHisDataAddOrUpdateRequest
|
||||
{
|
||||
VarietyId = newData.id,
|
||||
ValueType = nameof(MarginParamModel.UpDownLimit),
|
||||
Value = newPara.UpDownLimit,
|
||||
ValueDate = valdate
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
using System.Text;
|
||||
using YLErp.BLL;
|
||||
using YLErp.Models;
|
||||
|
||||
namespace YLErp.Modules.UnderlyingModule
|
||||
{
|
||||
public class VarietyHisDataService : YLBaseService
|
||||
{
|
||||
public VarietyHisDataService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public VarietyHisDataService(YLBaseService baseService) : base(baseService)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 删除品种历史数据
|
||||
/// </summary>
|
||||
public int RemoveHisData(int varietyId, DateTime valueDate, string valueType)
|
||||
{
|
||||
if (varietyId < 1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
valueDate = valueDate.Date;
|
||||
|
||||
var data = DbContext.VarietyHisData.FirstOrDefault(
|
||||
n => n.VarietyId == varietyId && n.ValueDate == valueDate && n.ValueType == valueType);
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
DbContext.VarietyHisData.Remove(data);
|
||||
return DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新品种历史数据
|
||||
/// </summary>
|
||||
public int AddOrUpdateHisData(VarietyHisDataAddOrUpdateRequest req, bool saveChanges = true)
|
||||
{
|
||||
if (req is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(req));
|
||||
}
|
||||
|
||||
if (saveChanges && (req.VarietyId < 1 || !DbContext.variety.Any(n => n.id == req.VarietyId)))
|
||||
{
|
||||
throw new ServiceException("品种数据 不存在");
|
||||
}
|
||||
|
||||
switch (req.ValueType)
|
||||
{
|
||||
case nameof(MarginParamModel.MarginRate):
|
||||
case nameof(MarginParamModel.UpDownLimit):
|
||||
case nameof(MarginParamModel.VolatilityRate): break;
|
||||
default: throw new ServiceException("ValueType 不支持:" + req.ValueType);
|
||||
}
|
||||
|
||||
var hisdata = DbContext.VarietyHisData.OrderByDescending(n => n.ValueDate).FirstOrDefault(
|
||||
n => n.VarietyId == req.VarietyId && n.ValueDate <= req.ValueDate && n.ValueType == req.ValueType);
|
||||
|
||||
if (hisdata != null)
|
||||
{
|
||||
var newValue = req.Value;
|
||||
|
||||
//如果新值和旧值一致则不需要处理
|
||||
if (newValue.HasValue && Math.Abs(newValue.Value - hisdata.Value) < 1e-6)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else if (!req.Value.HasValue)
|
||||
{
|
||||
return 0; //如果没有历史数据并且新值为null
|
||||
}
|
||||
|
||||
if (hisdata == null || hisdata.ValueDate < req.ValueDate)
|
||||
{
|
||||
hisdata = new VarietyHisData
|
||||
{
|
||||
VarietyId = req.VarietyId,
|
||||
ValueDate = req.ValueDate,
|
||||
ValueType = req.ValueType
|
||||
};
|
||||
|
||||
DbContext.VarietyHisData.Add(hisdata);
|
||||
}
|
||||
|
||||
hisdata.Value = req.Value ?? 0;
|
||||
|
||||
SetDBModelOpt(hisdata);
|
||||
|
||||
return saveChanges ? DbContext.SaveChanges() : 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 回写历史数据到主表
|
||||
/// </summary>
|
||||
public int BackHisDataToMainTable()
|
||||
{
|
||||
var db = DbContextFactory.GetYLDbContext();
|
||||
var valueDate = valuedateBLL.ValueDate;
|
||||
var startDate = valuedateBLL.ValueDate.AddDays(-3);
|
||||
var uhgQuery = from a in db.VarietyHisData
|
||||
where a.ValueDate >= startDate && a.ValueDate <= valueDate
|
||||
group a by new
|
||||
{
|
||||
a.VarietyId,
|
||||
a.ValueType
|
||||
} into aa
|
||||
select new
|
||||
{
|
||||
aa.Key.VarietyId,
|
||||
aa.Key.ValueType,
|
||||
ValueDate = aa.Max(n => n.ValueDate)
|
||||
};
|
||||
|
||||
var uhQuery = from a in uhgQuery
|
||||
join b in db.VarietyHisData on new { a.VarietyId, a.ValueType, a.ValueDate } equals new { b.VarietyId, b.ValueType, b.ValueDate }
|
||||
select new
|
||||
{
|
||||
b.VarietyId,
|
||||
b.Value,
|
||||
b.ValueType
|
||||
};
|
||||
|
||||
var hisdatas = uhQuery.ToArray();
|
||||
|
||||
if (!hisdatas.Any())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var sb = new StringBuilder(1000);
|
||||
|
||||
const string sqlfmtMarginRate = "update variety set Margin='{0}' WHERE id='{1}';";
|
||||
const string sqlfmtUpDownLimit = "update variety set UpLimit='{0}',DownLimit='{0}' WHERE id='{1}';";
|
||||
const string sqlfmtVolatilityRate = "update variety set VolatilityRate='{0}' WHERE id='{1}';";
|
||||
|
||||
foreach (var item in hisdatas)
|
||||
{
|
||||
switch (item.ValueType)
|
||||
{
|
||||
case nameof(MarginParamModel.MarginRate):
|
||||
sb.AppendFormat(sqlfmtMarginRate, item.Value.ToString("0.0#####"), item.VarietyId).AppendLine();
|
||||
break;
|
||||
case nameof(MarginParamModel.UpDownLimit):
|
||||
sb.AppendFormat(sqlfmtUpDownLimit, item.Value.ToString("0.0###%"), item.VarietyId).AppendLine();
|
||||
break;
|
||||
case nameof(MarginParamModel.VolatilityRate):
|
||||
sb.AppendFormat(sqlfmtVolatilityRate, item.Value.ToString("0.0###%"), item.VarietyId).AppendLine();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var sql = sb.ToString();
|
||||
LogFactory.GetLogger("回写品种历史数据到主表").Info(sql);
|
||||
return DbContext.Database.ExecuteSqlRaw(sql);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class VarietyHisDataAddOrUpdateRequest
|
||||
{
|
||||
public int VarietyId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 使用MarginParamModel的属性字段
|
||||
/// </summary>
|
||||
public string ValueType { get; set; }
|
||||
|
||||
public DateTime ValueDate { get; set; }
|
||||
|
||||
public double? Value { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,336 @@
|
||||
using BaseOUDAL;
|
||||
using System.Data;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using YLErp.Model;
|
||||
|
||||
namespace YLErp.Modules.ClientCashModule
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class VarietyMappingDeductService : YLBaseService
|
||||
{
|
||||
public VarietyMappingDeductService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public variety_mapping_deduct SaveClientVarietyConfig(variety_mapping_deduct req)
|
||||
{
|
||||
if (req is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(req));
|
||||
}
|
||||
|
||||
if (DbContext.variety_mapping_deduct.Any(x => x.id != req.id && x.VarietyId == req.VarietyId && x.VarietyIdOther == req.VarietyIdOther))
|
||||
{
|
||||
throw new Exception("同一客户同一品种不支持在同一天有多条配置记录");
|
||||
}
|
||||
|
||||
var varietyMappingDeduct = DbContext.variety_mapping_deduct.Find(req.id);
|
||||
if (varietyMappingDeduct == null)
|
||||
{
|
||||
varietyMappingDeduct = new variety_mapping_deduct();
|
||||
DbContext.variety_mapping_deduct.Add(varietyMappingDeduct);
|
||||
}
|
||||
|
||||
UpdateChanges(varietyMappingDeduct, req);
|
||||
|
||||
varietyMappingDeduct.OptDate = DateTime.Now;
|
||||
varietyMappingDeduct.OptId = UserId;
|
||||
varietyMappingDeduct.OptName = UserName;
|
||||
|
||||
DbContext.SaveChanges();
|
||||
|
||||
return varietyMappingDeduct;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导入抵扣品种对配置
|
||||
/// </summary>
|
||||
/// <param name="streamIn"></param>
|
||||
/// <param name="totalNum">当前文件中的目标期权总条数</param>
|
||||
/// <param name="successNum">成功入库的数量</param>
|
||||
public void ImportVarietyMappingDeductFromExcel(Stream streamIn, out int totalNum, out int successNum)
|
||||
{
|
||||
totalNum = 0;
|
||||
successNum = 0;
|
||||
|
||||
var rowIndex = 0;
|
||||
try
|
||||
{
|
||||
var ds = Office.ExcelHelper.ReadExcelAsDataSet(streamIn, new[] { 0 }, 0);
|
||||
|
||||
if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 2)
|
||||
{
|
||||
throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" };
|
||||
}
|
||||
|
||||
var table = ds.Tables[0];
|
||||
var reader = new DataRowReader(table);
|
||||
|
||||
rowIndex = 1;
|
||||
totalNum = table.Rows.Count - rowIndex;
|
||||
|
||||
using (var trans = BeginTransaction())
|
||||
{
|
||||
foreach (var row in table.Rows.Cast<DataRow>().Skip(1))
|
||||
{
|
||||
rowIndex++;
|
||||
|
||||
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
|
||||
{
|
||||
totalNum--;
|
||||
continue;
|
||||
}
|
||||
|
||||
reader.SetDataRow(row);
|
||||
|
||||
var varietyCode = reader.GetString("品种一");
|
||||
var varietyCodeOther = reader.GetString("品种二");
|
||||
|
||||
if (varietyCode == varietyCodeOther)
|
||||
{
|
||||
throw new ServiceException($"同一品种{varietyCode}不支持抵扣配置");
|
||||
}
|
||||
|
||||
var variety = DataCacheProvider.GetVarietyDataSource().GetData(varietyCode);
|
||||
if (variety == null)
|
||||
{
|
||||
throw new ServiceException($"品种{varietyCode}不存在");
|
||||
}
|
||||
var varietyOther = DataCacheProvider.GetVarietyDataSource().GetData(varietyCodeOther);
|
||||
if (varietyOther == null)
|
||||
{
|
||||
throw new ServiceException($"品种{varietyCodeOther}不存在");
|
||||
}
|
||||
|
||||
if (DbContext.variety_mapping_deduct.Any(x => x.VarietyId == variety.id && x.VarietyIdOther == varietyOther.id))
|
||||
{
|
||||
throw new ServiceException($"品种{varietyCode}和{varietyCodeOther}的配置已存在");
|
||||
}
|
||||
|
||||
var variety_mapping_deduct = new variety_mapping_deduct()
|
||||
{
|
||||
VarietyId = variety.id,
|
||||
VarietyIdOther = varietyOther.id,
|
||||
DPSR = reader.GetDouble("DPSR一", true) ?? 1,
|
||||
DPSROther = reader.GetDouble("DPSR二", true) ?? 1,
|
||||
ConcessionRate = reader.GetPercent("抵扣率", true) ?? 1,
|
||||
Unit = reader.GetDouble("Unit一", true) ?? 1,
|
||||
UnitOther = reader.GetDouble("Unit二", true) ?? 1,
|
||||
Index = reader.GetInt32("优先序号"),
|
||||
OptId = UserId,
|
||||
OptName = UserName,
|
||||
OptDate = DateTime.Now
|
||||
};
|
||||
|
||||
DbContext.variety_mapping_deduct.Add(variety_mapping_deduct);
|
||||
DbContext.SaveChanges();
|
||||
|
||||
successNum++;
|
||||
}
|
||||
|
||||
trans.Commit();
|
||||
}
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// trade_swap_flow
|
||||
/// </summary>
|
||||
public SearchListResult<variety_mapping_deduct> SearchVarietyMappingDeductList(VarietyMappingDeductReq req)
|
||||
{
|
||||
var query = from source in DbContext.variety_mapping_deduct select source;
|
||||
|
||||
if (string.IsNullOrEmpty(req.sidx))
|
||||
{
|
||||
req.sidx = "id";
|
||||
req.sord = "desc";
|
||||
}
|
||||
|
||||
var retListResult = query.ToSearchList(req);
|
||||
var varietyIds = retListResult.rows.Select(x => x.VarietyId).ToList();
|
||||
varietyIds.AddRange(retListResult.rows.Select(x => x.VarietyIdOther).ToList());
|
||||
varietyIds = varietyIds.Distinct().ToList();
|
||||
var varietys = DbContext.variety.Where(x => varietyIds.Contains(x.id)).ToList();
|
||||
foreach (var item in retListResult.rows)
|
||||
{
|
||||
var variety = varietys.FirstOrDefault(x => x.id == item.VarietyId);
|
||||
if (variety != null)
|
||||
{
|
||||
item.VarietyCode = variety.VarietyCode;
|
||||
}
|
||||
|
||||
var varietyOther = varietys.FirstOrDefault(x => x.id == item.VarietyIdOther);
|
||||
if (varietyOther != null)
|
||||
{
|
||||
item.VarietyCodeOther = varietyOther.VarietyCode;
|
||||
}
|
||||
}
|
||||
|
||||
return retListResult;
|
||||
}
|
||||
|
||||
#region---内部业务类----
|
||||
|
||||
class DataRowReader
|
||||
{
|
||||
DataRow _row;
|
||||
|
||||
readonly Dictionary<string, int> _colMap;
|
||||
|
||||
public DataRowReader(DataTable table)
|
||||
{
|
||||
var colCount = table.Columns.Count;
|
||||
|
||||
_colMap = new Dictionary<string, int>(colCount, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var row1 = table.Rows[0];
|
||||
var preCol1 = string.Empty;
|
||||
|
||||
for (var index = 0; index < colCount; index++)
|
||||
{
|
||||
var col1 = row1[index]?.ToString()?.Trim();
|
||||
if (!string.IsNullOrWhiteSpace(col1))
|
||||
{
|
||||
preCol1 = col1;
|
||||
}
|
||||
_colMap[preCol1] = index;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置datarow
|
||||
/// </summary>
|
||||
public void SetDataRow(DataRow row)
|
||||
{
|
||||
_row = row;
|
||||
}
|
||||
|
||||
public string GetString(string fieldName, bool required = false)
|
||||
{
|
||||
var str = _colMap.TryGetValue(fieldName, out var colIndex) ? _row[colIndex]?.ToString()?.Trim() : null;
|
||||
|
||||
if (required && string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
throw new ServiceException($"{fieldName} 必须填写");
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
public double? GetDoubleOrPercent(string fieldName, bool required, bool percent)
|
||||
{
|
||||
var str = GetString(fieldName, required);
|
||||
|
||||
if (!required && string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (percent && (percent = str.EndsWith("%")))
|
||||
{
|
||||
str = str.TrimEnd('%');
|
||||
}
|
||||
|
||||
return double.TryParse(str, out var num) ? (percent ? num / 100 : num) : throw new ServiceException($"{fieldName} 填写错误:{str}");
|
||||
}
|
||||
|
||||
public double? GetDouble(string fieldName, bool required = false)
|
||||
{
|
||||
var str = GetString(fieldName, required);
|
||||
|
||||
if (!required && string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return double.TryParse(str, out var num) ? num : throw new ServiceException($"{fieldName} 填写错误:{str}");
|
||||
}
|
||||
|
||||
//为了兼容模板修改导致的字段名称改变问题
|
||||
public double? GetDouble(string fieldName, string fieldName2, bool required = false)
|
||||
{
|
||||
var str = GetString(fieldName, false) ?? GetString(fieldName2, false);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
return required ? throw new ServiceException($"{fieldName} 必须填写") : (double?)null;
|
||||
}
|
||||
|
||||
return double.TryParse(str, out var num) ? num : throw new ServiceException($"{fieldName} 填写错误:{str}");
|
||||
}
|
||||
|
||||
public double? GetPercent(string fieldName, bool required = false)
|
||||
{
|
||||
var str = GetString(fieldName, required);
|
||||
|
||||
if (!required && string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var percent = str.EndsWith("%");
|
||||
|
||||
if (percent)
|
||||
{
|
||||
str = str.TrimEnd('%');
|
||||
}
|
||||
|
||||
return double.TryParse(str, out var num) ? (percent ? num / 100 : num) : throw new ServiceException($"{fieldName} 填写错误:{str}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取日期(不包括时间)
|
||||
/// </summary>
|
||||
public DateTime? GetDate(string fieldName, bool required = false)
|
||||
{
|
||||
var str = GetString(fieldName, required);
|
||||
|
||||
if (!required && string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (str.Length == 8 && Regex.IsMatch(str, @"^\d+$"))
|
||||
{
|
||||
return DateTime.TryParseExact(str, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt2) ? dt2 : throw new ServiceException($"{fieldName} 填写错误:{str}");
|
||||
}
|
||||
|
||||
return DateTime.TryParse(str, out var dt) ? dt.Date : throw new ServiceException($"{fieldName} 填写错误:{str}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public int? GetInt32(string fieldName, bool required = false)
|
||||
{
|
||||
var str = GetString(fieldName, required);
|
||||
|
||||
if (!required && string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return int.TryParse(str, out var num) ? num : throw new ServiceException($"{fieldName} 填写错误:{str}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,317 @@
|
||||
using BaseOUDAL;
|
||||
using System.Data;
|
||||
using System.Globalization;
|
||||
using System.Text.RegularExpressions;
|
||||
using YLErp.Model;
|
||||
|
||||
namespace YLErp.Modules.ClientCashModule
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public class VarietyPFEDeductService : YLBaseService
|
||||
{
|
||||
public VarietyPFEDeductService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public variety_pfe_deduct SaveVarietyPFEConfig(variety_pfe_deduct req)
|
||||
{
|
||||
if (req is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(req));
|
||||
}
|
||||
|
||||
if (DbContext.variety_pfe_deduct.Any(x => x.id != req.id && x.VarietyIds == req.VarietyIds))
|
||||
{
|
||||
throw new Exception("同一品种对不支持多条配置记录");
|
||||
}
|
||||
|
||||
var varietyPFEDeduct = DbContext.variety_pfe_deduct.Find(req.id);
|
||||
if (varietyPFEDeduct == null)
|
||||
{
|
||||
varietyPFEDeduct = new variety_pfe_deduct();
|
||||
DbContext.variety_pfe_deduct.Add(varietyPFEDeduct);
|
||||
}
|
||||
|
||||
UpdateChanges(varietyPFEDeduct, req);
|
||||
|
||||
varietyPFEDeduct.OptDate = DateTime.Now;
|
||||
varietyPFEDeduct.OptId = UserId;
|
||||
varietyPFEDeduct.OptName = UserName;
|
||||
|
||||
DbContext.SaveChanges();
|
||||
|
||||
return varietyPFEDeduct;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导入PFE抵扣品种系数配置
|
||||
/// </summary>
|
||||
/// <param name="streamIn"></param>
|
||||
/// <param name="totalNum">当前文件中的目标期权总条数</param>
|
||||
/// <param name="successNum">成功入库的数量</param>
|
||||
public void ImportVarietyPFEDeductFromExcel(Stream streamIn, out int totalNum, out int successNum)
|
||||
{
|
||||
totalNum = 0;
|
||||
successNum = 0;
|
||||
|
||||
var rowIndex = 0;
|
||||
try
|
||||
{
|
||||
var ds = Office.ExcelHelper.ReadExcelAsDataSet(streamIn, new[] { 0 }, 0);
|
||||
|
||||
if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 2)
|
||||
{
|
||||
throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" };
|
||||
}
|
||||
|
||||
var table = ds.Tables[0];
|
||||
var reader = new DataRowReader(table);
|
||||
|
||||
rowIndex = 1;
|
||||
totalNum = table.Rows.Count - rowIndex;
|
||||
|
||||
using (var trans = BeginTransaction())
|
||||
{
|
||||
foreach (var row in table.Rows.Cast<DataRow>().Skip(1))
|
||||
{
|
||||
rowIndex++;
|
||||
|
||||
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
|
||||
{
|
||||
totalNum--;
|
||||
continue;
|
||||
}
|
||||
|
||||
reader.SetDataRow(row);
|
||||
|
||||
var varietyCodes = reader.GetString("品种");
|
||||
var varietyCodeList = varietyCodes.Split(',', ',').ToList();
|
||||
List<Variety> varietys = new List<Variety>();
|
||||
varietyCodeList.ForEach(x =>
|
||||
{
|
||||
var variety = DataCacheProvider.GetVarietyDataSource().GetData(x);
|
||||
if (variety == null)
|
||||
{
|
||||
throw new ServiceException($"品种{x}不存在");
|
||||
}
|
||||
else
|
||||
{
|
||||
varietys.Add(variety);
|
||||
}
|
||||
});
|
||||
var varietyIds = string.Join(",", varietys.Select(x => x.id));
|
||||
|
||||
if (DbContext.variety_pfe_deduct.Any(x => x.VarietyIds == varietyIds))
|
||||
{
|
||||
throw new ServiceException($"品种{varietyCodes}的配置已存在");
|
||||
}
|
||||
|
||||
var variety_pfe_deduct = new variety_pfe_deduct()
|
||||
{
|
||||
VarietyIds = varietyIds,
|
||||
Rate = reader.GetPercent("抵扣系数", true) ?? 1,
|
||||
OptId = UserId,
|
||||
OptName = UserName,
|
||||
OptDate = DateTime.Now
|
||||
};
|
||||
|
||||
DbContext.variety_pfe_deduct.Add(variety_pfe_deduct);
|
||||
DbContext.SaveChanges();
|
||||
|
||||
successNum++;
|
||||
}
|
||||
|
||||
trans.Commit();
|
||||
}
|
||||
}
|
||||
catch (ServiceException se)
|
||||
{
|
||||
if (se.Tag != null)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
throw new ServiceException($"第{rowIndex}行,{se.Message}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogFactory.GetLogger("导入PFE抵扣品种系数配置").Error(ex);
|
||||
throw new ServiceException($"第{rowIndex}行,发生错误:{ex.Message}", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// trade_swap_flow
|
||||
/// </summary>
|
||||
public SearchListResult<variety_pfe_deduct> SearchVarietyPFEDeductList(VarietyMappingDeductReq req)
|
||||
{
|
||||
var query = from source in DbContext.variety_pfe_deduct select source;
|
||||
|
||||
if (string.IsNullOrEmpty(req.sidx))
|
||||
{
|
||||
req.sidx = "id";
|
||||
req.sord = "desc";
|
||||
}
|
||||
|
||||
var retListResult = query.ToSearchList(req);
|
||||
|
||||
foreach (var item in retListResult.rows)
|
||||
{
|
||||
var varietyIds = item.VarietyIds.Split(',');
|
||||
var varietys = DbContext.variety.Where(x => varietyIds.Contains(x.id.ToString()));
|
||||
item.VarietyCodes = string.Join(",", varietys.Select(x => x.VarietyCode));
|
||||
}
|
||||
|
||||
return retListResult;
|
||||
}
|
||||
|
||||
#region---内部业务类----
|
||||
|
||||
class DataRowReader
|
||||
{
|
||||
DataRow _row;
|
||||
|
||||
readonly Dictionary<string, int> _colMap;
|
||||
|
||||
public DataRowReader(DataTable table)
|
||||
{
|
||||
var colCount = table.Columns.Count;
|
||||
|
||||
_colMap = new Dictionary<string, int>(colCount, StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
var row1 = table.Rows[0];
|
||||
var preCol1 = string.Empty;
|
||||
|
||||
for (var index = 0; index < colCount; index++)
|
||||
{
|
||||
var col1 = row1[index]?.ToString()?.Trim();
|
||||
if (!string.IsNullOrWhiteSpace(col1))
|
||||
{
|
||||
preCol1 = col1;
|
||||
}
|
||||
_colMap[preCol1] = index;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置datarow
|
||||
/// </summary>
|
||||
public void SetDataRow(DataRow row)
|
||||
{
|
||||
_row = row;
|
||||
}
|
||||
|
||||
public string GetString(string fieldName, bool required = false)
|
||||
{
|
||||
var str = _colMap.TryGetValue(fieldName, out var colIndex) ? _row[colIndex]?.ToString()?.Trim() : null;
|
||||
|
||||
if (required && string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
throw new ServiceException($"{fieldName} 必须填写");
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
public double? GetDoubleOrPercent(string fieldName, bool required, bool percent)
|
||||
{
|
||||
var str = GetString(fieldName, required);
|
||||
|
||||
if (!required && string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (percent && (percent = str.EndsWith("%")))
|
||||
{
|
||||
str = str.TrimEnd('%');
|
||||
}
|
||||
|
||||
return double.TryParse(str, out var num) ? (percent ? num / 100 : num) : throw new ServiceException($"{fieldName} 填写错误:{str}");
|
||||
}
|
||||
|
||||
public double? GetDouble(string fieldName, bool required = false)
|
||||
{
|
||||
var str = GetString(fieldName, required);
|
||||
|
||||
if (!required && string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return double.TryParse(str, out var num) ? num : throw new ServiceException($"{fieldName} 填写错误:{str}");
|
||||
}
|
||||
|
||||
//为了兼容模板修改导致的字段名称改变问题
|
||||
public double? GetDouble(string fieldName, string fieldName2, bool required = false)
|
||||
{
|
||||
var str = GetString(fieldName, false) ?? GetString(fieldName2, false);
|
||||
|
||||
if (string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
return required ? throw new ServiceException($"{fieldName} 必须填写") : (double?)null;
|
||||
}
|
||||
|
||||
return double.TryParse(str, out var num) ? num : throw new ServiceException($"{fieldName} 填写错误:{str}");
|
||||
}
|
||||
|
||||
public double? GetPercent(string fieldName, bool required = false)
|
||||
{
|
||||
var str = GetString(fieldName, required);
|
||||
|
||||
if (!required && string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var percent = str.EndsWith("%");
|
||||
|
||||
if (percent)
|
||||
{
|
||||
str = str.TrimEnd('%');
|
||||
}
|
||||
|
||||
return double.TryParse(str, out var num) ? (percent ? num / 100 : num) : throw new ServiceException($"{fieldName} 填写错误:{str}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取日期(不包括时间)
|
||||
/// </summary>
|
||||
public DateTime? GetDate(string fieldName, bool required = false)
|
||||
{
|
||||
var str = GetString(fieldName, required);
|
||||
|
||||
if (!required && string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (str.Length == 8 && Regex.IsMatch(str, @"^\d+$"))
|
||||
{
|
||||
return DateTime.TryParseExact(str, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt2) ? dt2 : throw new ServiceException($"{fieldName} 填写错误:{str}");
|
||||
}
|
||||
|
||||
return DateTime.TryParse(str, out var dt) ? dt.Date : throw new ServiceException($"{fieldName} 填写错误:{str}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public int? GetInt32(string fieldName, bool required = false)
|
||||
{
|
||||
var str = GetString(fieldName, required);
|
||||
|
||||
if (!required && string.IsNullOrWhiteSpace(str))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return int.TryParse(str, out var num) ? num : throw new ServiceException($"{fieldName} 填写错误:{str}");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user