Files
zszq-trs/YLErpDAL/Modules/UnderlyingModule/StockBlackWhiteService.cs
T
2024-05-09 14:06:26 +08:00

448 lines
20 KiB
C#

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;
}
}
}