Files
zszq-trs/YLErpDAL/Modules/ExchangeTradeModule/ExchangeTradeSyncApiService.cs
T

338 lines
12 KiB
C#

using BaseOUDAL;
using YLErp.BLL;
using YLErp.DBModels.Enums;
using YLErp.DBModels.Helpers;
using YLErp.QdpModule;
namespace YLErp.Modules.ExchangeTradeModule
{
/// <summary>
/// 对冲交易同步API服务
/// </summary>
public class ExchangeTradeSyncApiService : ExchangeTradeSaveServiceBase
{
public ExchangeTradeSyncApiService(YLBaseService baseService) : base(baseService)
{
}
public ExchangeTradeSyncApiService(OptUserInfo userInfo) : base(userInfo)
{
}
public int Save(ExchangeTradeSaveApiReq req, string tradeSource)
{
if (req.TradeDate == DateTime.MinValue)
{
throw new ServiceException("交易日期 必须填写");
}
if (!req.IsHistory && req.TradeDate < valuedateBLL.ValueDate)
{
throw new ServiceException("交易日期 不能小于系统日期:" + valuedateBLL.ValueDate.ToString("yyyy-MM-dd"));
}
if (string.IsNullOrWhiteSpace(req.UnderlyingCode))
{
throw new ServiceException("交易产品代码 必须填写");
}
if (string.IsNullOrWhiteSpace(req.BuySell))
{
throw new ServiceException("交易方向 必须填写");
}
if (string.IsNullOrWhiteSpace(req.ExchangeAccountCode))
{
throw new ServiceException("交易账户代码 必须填写");
}
switch (req.TradeType)
{
case "股票":
case "商品现货":
case "场内期权":
case "利率债":
case "信用债":
case "其它债券":
break;
case "商品期货":
if (req.UnderlyingCode.Length > 8)
{
req.TradeType = "场内期权";
}
break;
default:
throw new ServiceException("交易类型未能识别:" + req.TradeType);
}
//20220415:金仕达接口给的商品期货数据,如果是来源于场内期权行权产生的,则会和场内期权交易编号一致
ExchangeTrade dbTrade = null;
var canUpdate = false;
//两个交易日内交易编号相同的在数据库存在数据,就忽略不做处理;不存在,就插入一条交易日为上一日的交易。
if (req.TradeNumber.EndsWith("_dzrh_"))
{
var lastTradeDate = QdpCalendarHelper.GetNonHolidayDefore(req.TradeDate.AddDays(-1));
if (DbContext.ExchangeTrade.Any(x => (x.TradeDate == req.TradeDate || x.TradeDate == lastTradeDate) && x.TradeNumber == req.TradeNumber))
{
return 0;
}
else
{
req.TradeDate = lastTradeDate;
}
}
else
{
dbTrade = DbContext.ExchangeTrade.FirstOrDefault(x => x.TradeDate == req.TradeDate && x.TradeType == req.TradeType && x.TradeNumber == req.TradeNumber);
canUpdate = dbTrade != null
//&& req.TradeType == dbTrade.TradeType
&& req.BuySell == dbTrade.TradeSide
&& req.ExchangeAccountCode.Equals(dbTrade.ExchangeAccountCode, StringComparison.OrdinalIgnoreCase)
&& req.UnderlyingCode.Equals(dbTrade.TradeType == "场内期权" ? dbTrade.OptionCode : dbTrade.UnderlyingCode, StringComparison.OrdinalIgnoreCase);
}
var reqTrade = PrepareReqTrad(req, tradeSource);
SaveExchangeTradePosition(reqTrade, canUpdate ? dbTrade : null);
if (canUpdate)
{
dbTrade.UnderlyingCode = reqTrade.UnderlyingCode;
dbTrade.TradeSinglePrice = reqTrade.TradeSinglePrice;
dbTrade.Notional = reqTrade.Notional;
dbTrade.TradeAmount = reqTrade.TradeAmount;
dbTrade.TradeLots = reqTrade.TradeLots;
dbTrade.TraderId = reqTrade.TraderId;
dbTrade.TraderName = reqTrade.TraderName;
dbTrade.UnderlyingId = reqTrade.UnderlyingId;
dbTrade.MaturityDate = reqTrade.MaturityDate;
dbTrade.OptionStrike = reqTrade.OptionStrike;
dbTrade.OptionType = reqTrade.OptionType;
dbTrade.ExerciseMode = reqTrade.ExerciseMode;
dbTrade.AssetBookId = reqTrade.AssetBookId;
dbTrade.ExchangeAccountId = reqTrade.ExchangeAccountId;
dbTrade.InstrumentType = reqTrade.InstrumentType;
dbTrade.OptDate = DateTime.Now;
}
else
{
DbContext.ExchangeTrade.Add(reqTrade);
}
return DbContext.SaveChanges();
}
//将req转换交易对象
private ExchangeTrade PrepareReqTrad(ExchangeTradeSaveApiReq req, string tradeSource = "下单同步")
{
var td = new ExchangeTrade
{
IsValid = true,
TradeType = req.TradeType,
TradeDate = req.TradeDate,
TradeNumber = req.TradeNumber,
TradeSide = req.BuySell,
TradeSinglePrice = req.TradePrice,
UnderlyingCode = req.UnderlyingCode,
ExchangeAccountCode = req.ExchangeAccountCode,
Commission = 0,
CommissionType = CommissionType.系统计算,
OptId = 0,
OptDate = DateTime.Now,
OptName = UserName,
CreateTime = DateTime.Now,
TradeSource = tradeSource,
Notional = 0,
TradeAmount = 0,
TradeLots = 0,
TraderId = 0,
TraderName = UserName,
UnderlyingId = 0,
MaturityDate = null,
OptionCode = null,
OptionStrike = null,
OptionType = null,
ExerciseMode = null,
AssetBookId = 0,
ExchangeAccountId = 0,
InstrumentType = null,
Comments = null,
};
var contractSize = 0d;
if (td.TradeType == "场内期权")
{
SetTradeOptionInfo(td, td.UnderlyingCode, out var option, false);
contractSize = option.ContractSize;
}
//标的信息
var um = DbContext.underlying_manager.Where(un => un.UnderlyingCode == td.UnderlyingCode)
.Select(n => new
{
n.id,
n.UnderlyingType,
n.MaturityDate,
n.UnderlyingTypeId,
n.UnderlyingInstrumentType,
n.ContractSize
}).FirstOrDefault();
if (um == null)
{
throw new ServiceException($"未找到标的信息:" + td.UnderlyingCode);
}
td.UnderlyingId = um.id;
td.InstrumentType = um.UnderlyingInstrumentType;
if (td.TradeType != "场内期权")
{
td.MaturityDate = um.MaturityDate;
}
//交易数量
if (td.TradeType == "股票")
{
td.TradeLots = req.Lots / 100;
td.Notional = td.TradeAmount = req.Lots;
}
else
{
if (contractSize < 1)
{
contractSize = um.ContractSize;
}
var variety = DbContext.variety.Where(n => n.id == um.UnderlyingTypeId).FirstOrDefault();
if (variety == null)
{
throw new ServiceException($"未找到{td.UnderlyingCode}的品种信息");
}
var CountRatio = VarietyHelper.GetCountRatio(variety.QuoteUnit);
if (contractSize > 1)
{
td.TradeLots = req.Lots;
td.Notional = req.Lots * contractSize;
td.TradeAmount = td.Notional / variety.CountRatio;
}
else
{
td.TradeLots = req.Lots;
td.Notional = req.Lots * (variety.TradeUnitValue ?? 1);
td.TradeAmount = td.Notional / variety.CountRatio;
}
}
//簿记等信息
PrepareBook(td, um.UnderlyingTypeId);
if (req.Commission.HasValue)
{
td.Commission = req.Commission.Value;
td.CommissionType = CommissionType.手动录入;
}
return td;
}
//为trade准备对冲账户/簿记/交易员信息
private void PrepareBook(ExchangeTrade td, int varietyId)
{
var query = from a in DbContext.exchange_account
join b in DbContext.assetunit on a.DefaultBookId equals b.id into bs
from b in bs.DefaultIfEmpty()
where a.AccountCode == td.ExchangeAccountCode && a.Status == 1
select new
{
AccountId = a.id,
a.AccountCode,
a.VarietyIds,
a.TraderIds,
BookId = b != null ? b.id : 0,
BookName = b != null ? b.Name : "",
a.Description
};
var accbooks = query.ToList();
if (accbooks.Count == 0)
{
throw new ServiceException($"对冲账户'{td.ExchangeAccountCode}'在系统中不存在");
}
var accbook = accbooks[0];
var commaVarietyId = $",{varietyId},";
if (accbooks.Count == 1)
{
if (varietyId > 0 && !(string.IsNullOrWhiteSpace(accbook.VarietyIds) || string.Concat(",", accbook.VarietyIds.Trim(), ",").Contains(commaVarietyId)))
{
throw new ServiceException($"对冲账户'{td.ExchangeAccountCode}'配置品种不包含此交易的品种");
}
}
else if (varietyId > 0)
{
accbook = accbooks.FirstOrDefault(n => string.Concat(",", n.VarietyIds.Trim(), ",").Contains(commaVarietyId))
?? accbooks.FirstOrDefault(n => string.IsNullOrWhiteSpace(n.VarietyIds));
if (accbook == null)
{
throw new ServiceException($"对冲账户'{td.ExchangeAccountCode}'配置品种不包含此交易的品种");
}
}
//对冲账户
td.ExchangeAccountId = accbook.AccountId;
td.ExchangeAccountCode = accbook.AccountCode;
//簿记帐户
if (accbook.BookId < 1)
{
throw new ServiceException($"对冲账户'{td.ExchangeAccountCode}'没有找到簿记账户");
}
td.AssetBookId = accbook.BookId;
//交易员信息
var traderId = td.TraderId;
var trader = traderId > 0 ? UserBLL.GetById(traderId) : null;
if (trader == null)
{
traderId = DataConvert.ConvertCommaValuesToInt32Array(accbook.TraderIds).FirstOrDefault();
if (traderId > 0)
{
trader = UserBLL.GetById(traderId);
}
}
td.TraderId = trader?.Id ?? UserId;
td.TraderName = (trader == null && !string.IsNullOrWhiteSpace(accbook?.Description)) ? accbook.Description.Trim() : trader?.Name ?? UserName ?? "系统";
}
}
}