从山证v2.3.0拷贝

This commit is contained in:
吴方海
2024-05-09 14:06:26 +08:00
parent 566ff33259
commit f9d8a256a6
4471 changed files with 1203456 additions and 9 deletions
@@ -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
}
}