263 lines
8.4 KiB
C#
263 lines
8.4 KiB
C#
using BaseOUDAL;
|
|
using YLErp.DBModels.Enums;
|
|
using YLErp.DBModels.Helpers;
|
|
using YLErp.Model.Enum;
|
|
|
|
namespace YLErp.Modules.ExchangeTradeModule
|
|
{
|
|
/// <summary>
|
|
/// 标的交易保存服务
|
|
/// </summary>
|
|
public class ExchangeTradeSaveService : ExchangeTradeSaveServiceBase
|
|
{
|
|
public ExchangeTradeSaveService(YLBaseService baseService) : base(baseService)
|
|
{
|
|
|
|
}
|
|
|
|
public ExchangeTradeSaveService(OptUserInfo userInfo) : base(userInfo)
|
|
{
|
|
|
|
}
|
|
|
|
public ExchangeTrade Save(ExchangeTrade req, TradeSourceEnum source)
|
|
{
|
|
var isAddNew = req.id == 0;
|
|
|
|
Prepare(req, source, isAddNew);
|
|
|
|
if (isAddNew)
|
|
{
|
|
DbContext.ExchangeTrade.Add(req);
|
|
SaveExchangeTradePosition(req, null);
|
|
DbContext.SaveChanges();
|
|
return req;
|
|
}
|
|
else
|
|
{
|
|
var dbTrade = DbContext.ExchangeTrade.Find(req.id);
|
|
|
|
if (dbTrade == null)
|
|
{
|
|
throw new ServiceException("保存失败,数据不存在");
|
|
}
|
|
|
|
req.CreateTime = dbTrade.CreateTime;
|
|
req.TradeNumber = dbTrade.TradeNumber;
|
|
if (req.IsValid)
|
|
{
|
|
SaveExchangeTradePosition(req, dbTrade);
|
|
}
|
|
else
|
|
{
|
|
InValidTrade(req.id);
|
|
}
|
|
|
|
|
|
UpdateEntity(dbTrade, req);
|
|
DbContext.SaveChanges();
|
|
|
|
return dbTrade;
|
|
}
|
|
}
|
|
|
|
private void Prepare(ExchangeTrade req, TradeSourceEnum source, bool isAddNew)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(req.TradeType))
|
|
{
|
|
throw new ServiceException("交易类型 必须填写");
|
|
}
|
|
|
|
if (!ConsTrade.TradeTypesForHedge.Contains(req.TradeType)&&!ConsTrade.BondTypeList.Contains(req.TradeType))
|
|
{
|
|
throw new ServiceException("程序错误,标的交易类型不支持:" + req.TradeType);
|
|
}
|
|
|
|
//准备交易保存
|
|
PrepareSave(req);
|
|
|
|
req.OptId = UserId;
|
|
req.OptName = UserName;
|
|
req.OptDate = OptDate;
|
|
|
|
if (isAddNew)
|
|
{
|
|
req.TradeSource = source.ToString();
|
|
|
|
if (string.IsNullOrWhiteSpace(req.TradeNumber))
|
|
{
|
|
req.TradeNumber = DateTime.Now.ToString("yyyyMMddHHmmssfff");
|
|
}
|
|
|
|
req.IsValid = true;
|
|
req.CreateTime = DateTime.Now;
|
|
}
|
|
}
|
|
|
|
//准备交易基础信息(标的、簿记、交易日期)
|
|
private void PrepareSave(ExchangeTrade req)
|
|
{
|
|
if (req.TradeDate.Year < 2000)
|
|
{
|
|
throw new ServiceException("交易日期 填写错误:" + req.TradeDate.ToString("yyyy-MM-dd"));
|
|
}
|
|
|
|
ExchangeListOption exOption = null;
|
|
|
|
if (req.TradeType == "场内期权")
|
|
{
|
|
SetTradeOptionInfo(req, req.OptionCode, out exOption);
|
|
}
|
|
|
|
//标的信息
|
|
SetTradeUnderlyingInfo(req, req.UnderlyingCode, out var um);
|
|
|
|
//--------------------------------------
|
|
// 簿记帐户
|
|
//--------------------------------------
|
|
if (req.AssetBookId < 1)
|
|
{
|
|
throw new ServiceException("请选择簿记账户");
|
|
}
|
|
|
|
var assetUnit = DbContext.assetunit.Where(n => n.id == req.AssetBookId)
|
|
.Select(n => new AssetUnitDto { id = n.id, Name = n.Name, TraderIds = n.TraderIds, UserGroup = n.UserGroup }).FirstOrDefault();
|
|
|
|
if (assetUnit == null)
|
|
{
|
|
throw new ServiceException("簿记账户不存在");
|
|
}
|
|
|
|
//--------------------------------------
|
|
// 交易员信息
|
|
//--------------------------------------
|
|
|
|
//有交易员id,通过id查名字
|
|
if (req.TraderId > 0)
|
|
{
|
|
req.TraderName = UserBLL.GetNameById(req.TraderId);
|
|
}
|
|
else
|
|
{
|
|
//当前登录用户作为交易员
|
|
req.TraderId = UserId;
|
|
req.TraderName = UserName;
|
|
}
|
|
|
|
//--------------------------------------
|
|
// 对冲帐户
|
|
//--------------------------------------
|
|
if (req.ExchangeAccountId > 0)
|
|
{
|
|
req.ExchangeAccountCode = DbContext.exchange_account.Where(n => n.id == req.ExchangeAccountId).Select(n => n.AccountCode).FirstOrDefault();
|
|
}
|
|
|
|
//--------------------------------------
|
|
// 检查交易权限
|
|
//--------------------------------------
|
|
if (req.TraderId < 1)
|
|
{
|
|
throw new ServiceException("请选择交易员");
|
|
}
|
|
|
|
//不检查:必须是交易员角色
|
|
//不检查:交易用户组必须和簿记账户一致
|
|
//不检查:交易员不在所选簿记中,请重新选择簿记
|
|
//不检查:交易员具有交易标的的交易权限
|
|
|
|
//--------------------------------------
|
|
// 手续费
|
|
//--------------------------------------
|
|
switch (req.CommissionType)
|
|
{
|
|
case CommissionType.不收取:
|
|
case CommissionType.系统计算:
|
|
req.Commission = 0;
|
|
break;
|
|
default:
|
|
if (req.Commission < 0)
|
|
{
|
|
throw new ServiceException("请填写有效的交易手续费");
|
|
}
|
|
break;
|
|
}
|
|
|
|
//2020-09-11 改为以TradeAmount为主
|
|
|
|
if (req.TradeAmount < 1e-5)
|
|
{
|
|
throw new ServiceException("交易数量必须大于0");
|
|
}
|
|
|
|
if (req.TradeType != "场内期权")
|
|
{
|
|
req.Notional = req.TradeAmount * um.CountRatio;
|
|
req.TradeLots = req.Notional / um.ContractSize;
|
|
}
|
|
else
|
|
{
|
|
req.Notional = req.TradeAmount;
|
|
req.TradeLots = req.Notional / (exOption.ContractSize < 1 ? um.ContractSize : exOption.ContractSize);
|
|
}
|
|
|
|
//验证股票结构类型,只能股票标的,商品期货只能期货
|
|
switch (req.TradeType)
|
|
{
|
|
case "股票":
|
|
if (!um.CalcTypeIsStock())
|
|
{
|
|
throw new ServiceException("股票交易类型必须使用股票标的");
|
|
}
|
|
break;
|
|
case "商品期货":
|
|
if (!um.IsFutures())
|
|
{
|
|
throw new ServiceException("商品期货交易类型必须填写期货标的");
|
|
}
|
|
break;
|
|
case "商品现货":
|
|
if (!um.IsCommoditySpot())
|
|
{
|
|
throw new ServiceException("商品现货交易类型必须填写商品现货标的");
|
|
}
|
|
break;
|
|
case "场内期权":
|
|
break;
|
|
}
|
|
|
|
if (req.TradeType != "场内期权")
|
|
{
|
|
req.OptionType = string.Empty;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 删除交易
|
|
/// </summary>
|
|
public void InValidTrade(int id)
|
|
{
|
|
var dbTrade = DbContext.ExchangeTrade.Find(id);
|
|
|
|
if (dbTrade == null)
|
|
{
|
|
throw new ServiceException("找不到交易信息");
|
|
}
|
|
|
|
dbTrade.IsValid = false;
|
|
|
|
//清除对冲交易持仓
|
|
var para = PrepareTradePositionParam(dbTrade);
|
|
var dbPosition = DbContext.TradePosition.FirstOrDefault(para.predicate);
|
|
if (dbPosition != null)
|
|
{
|
|
var dbNotional = TradeHelper.GetPositionNotional(para.tradeSide, dbTrade.Notional);
|
|
dbPosition.Position -= dbNotional;
|
|
dbPosition.PositionCost -= dbNotional * dbTrade.TradeSinglePrice;
|
|
dbPosition.UpdateTime = OptDate;
|
|
}
|
|
|
|
DbContext.SaveChanges();
|
|
}
|
|
}
|
|
}
|