从山证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,82 @@
using Newtonsoft.Json;
namespace YLErp.Modules.TradeModule.ApiModule
{
/// <summary>
/// 期权交易查询导出请求
/// </summary>
public class OtcOptionTradeExportRequest
{
/// <summary>
/// 结构类型
/// </summary>
[JsonConverter(typeof(StringArrayConverter))]
public IEnumerable<string> TradeTypes { get; set; }
/// <summary>
/// 交易状态
/// </summary>
[JsonConverter(typeof(StringArrayConverter))]
public IEnumerable<string> TradeStatus { get; set; }
/// <summary>
/// 簿记账户名称
/// </summary>
[JsonConverter(typeof(StringArrayConverter))]
public IEnumerable<string> AssetBookNames { get; set; }
/// <summary>
/// 交易员名称
/// </summary>
[JsonConverter(typeof(StringArrayConverter))]
public IEnumerable<string> TraderNames { get; set; }
/// <summary>
/// 交易对手方名称
/// </summary>
[JsonConverter(typeof(StringArrayConverter))]
public IEnumerable<string> ClientNames { get; set; }
/// <summary>
/// 交易对手方编号,优先使用
/// </summary>
[JsonConverter(typeof(StringArrayConverter))]
public IEnumerable<string> ClientNumbers { get; set; }
/// <summary>
/// 交易编号
/// </summary>
public string TradeNumber { get; set; }
/// <summary>
/// 标的代码
/// </summary>
[JsonConverter(typeof(StringArrayConverter))]
public IEnumerable<string> UnderlyingCodes { get; set; }
/// <summary>
/// 交易方向买入|卖出
/// </summary>
public string BuySell { get; set; }
/// <summary>
/// 看涨看跌 Call|Put
/// </summary>
public string OptionType { get; set; }
/// <summary>
/// 行权方式:American|European
/// </summary>
public string ExerciseMode { get; set; }
/// <summary>
/// 成交日期筛选的起始日期, 格式: yyyy-MM-dd
/// </summary>
public DateTime? TradeDateStart { get; set; }
/// <summary>
/// 成交日期筛选的结束日期, 格式: yyyy-MM-dd
/// </summary>
public DateTime? TradeDateEnd { get; set; }
}
}
@@ -0,0 +1,122 @@
using YLErp.Model;
using YLErp.Modules.TradeModule.QueryModule;
namespace YLErp.Modules.TradeModule.ApiModule
{
/// <summary>
/// 场外期权交易导出服务
/// </summary>
public class OtcOptionTradeExportService
{
/// <summary>
///
/// </summary>
public byte[] ExportToExcel(OtcOptionTradeExportRequest queryModel)
{
var req = new TradeReq
{
TradeTypesList = queryModel.TradeTypes?.ToList(),
TradeStatusList = queryModel.TradeStatus?.ToList(),
TradeNumber = queryModel.TradeNumber,
UnderlyingCodeList = queryModel.UnderlyingCodes?.ToList(),
BuySell = queryModel.BuySell,
OptionType = queryModel.OptionType,
ExerciseMode = queryModel.ExerciseMode,
TradeDateEnd = queryModel.TradeDateEnd ?? default,
TradeDateStart = queryModel.TradeDateStart ?? default
};
//簿记账户名称
req.AssetIdList = GetAssetIds(queryModel.AssetBookNames);
//交易员名称
req.TraderNamesList = GetTraderId(queryModel.TraderNames);
//客户 优先使用客户编号
req.ClientIdsInt = GetClientIds(queryModel.ClientNumbers, queryModel.ClientNames);
return new OtcTradeListExportService(OptUserInfo.SystemUser).ExportOptionTradeListToExcel(req, new TradeQueryRequest
{
ShowAllTrades = true,
UserAssetUnits = null,
VolType = "持仓"
});
}
/// <summary>
/// 获取簿记账户id
/// </summary>
private List<int> GetAssetIds(IEnumerable<string> assetBookNames)
{
if (assetBookNames == null || !assetBookNames.HasNonEmptyItem())
{
return null;
}
var list = DataCacheProvider.GetAssetUnitDataSource().AsQueryable()
.Where(x => assetBookNames.Contains(x.Name)).Select(x => x.id).ToList();
if (!list.Any())
{
list.Add(-1);
}
return list;
}
/// <summary>
/// 返回交易员ID
/// </summary>
private List<int> GetTraderId(IEnumerable<string> traderNames)
{
if (traderNames == null || !traderNames.HasNonEmptyItem())
{
return null;
}
using (var sysdb = DbContextFactory.GetErpBaseContext())
{
var list = sysdb.SystemUsers.Where(su => traderNames.Contains(su.LoginName)).Select(n => n.Id).ToList();
if (!list.Any())
{
list.Add(-1);
}
return list;
}
}
/// <summary>
/// 根据交易对手方编号或名称返回交易对手方ID
/// </summary>
private List<int> GetClientIds(IEnumerable<string> clientNumbers, IEnumerable<string> clientNames)
{
List<int> list = null;
//编号优先,有编号则不使用客户名称匹配
if (clientNumbers != null && clientNumbers.HasNonEmptyItem())
{
list = DataCacheProvider.GetClientDataSource().AsQueryable()
.Where(x => clientNumbers.Contains(x.Number)).Select(x => x.id).ToList();
}
else if (clientNames != null && clientNames.HasNonEmptyItem())
{
list = DataCacheProvider.GetClientDataSource().AsQueryable()
.Where(x => clientNames.Contains(x.Name)).Select(x => x.id).ToList();
}
if (list == null)
{
return null;
}
if (!list.Any())
{
list.Add(-1);
}
return list;
}
}
}
@@ -0,0 +1,10 @@
namespace YLErp.Modules.TradeModule.ApiModule
{
/// <summary>
/// 单笔交易查询
/// </summary>
public class SingleTradeQueryModel
{
public string TradeNumber { get; set; }
}
}
@@ -0,0 +1,44 @@
using Newtonsoft.Json;
namespace YLErp.Modules.TradeModule.ApiModule
{
/// <summary>
/// api/v2/tradeDetailList
/// </summary>
public class TradeDetailQueryApiV2Request
{
/// <summary>
/// 结构类型
/// </summary>
[JsonConverter(typeof(StringArrayConverter))]
public IEnumerable<string> StructureTypes { get; set; }
/// <summary>
/// 交易状态
/// </summary>
[JsonConverter(typeof(StringArrayConverter))]
public IEnumerable<string> TradeStatus { get; set; }
/// <summary>
/// 交易对手方名称
/// </summary>
[JsonConverter(typeof(StringArrayConverter))]
public IEnumerable<string> ClientNames { get; set; }
/// <summary>
/// 交易对手方编号,优先使用
/// </summary>
[JsonConverter(typeof(StringArrayConverter))]
public IEnumerable<string> ClientNumbers { get; set; }
/// <summary>
/// 操作起始时间,格式: yyyy-MM-dd HH:mm:ss
/// </summary>
public DateTime OptDate { get; set; }
/// <summary>
/// 是否包含组合主交易
/// </summary>
public bool IncludeGroupMain { get; set; }
}
}
@@ -0,0 +1,236 @@
using System.Data;
using System.Linq.Expressions;
namespace YLErp.Modules.TradeModule.ApiModule
{
/// <summary>
/// api/v2/tradeDetailList
/// </summary>
public class TradeDetailQueryApiV2Service : YLBaseService
{
public TradeDetailQueryApiV2Service(OptUserInfo userInfo) : base(userInfo)
{
}
public TradeDetailQueryApiV2Service(YLBaseService baseService) : base(baseService)
{
}
/// <summary>
///
/// </summary>
public IEnumerable<TradeDetailQueryApiV2Result> GetList(TradeDetailQueryApiV2Request queryModel)
{
if (queryModel.OptDate == DateTime.MinValue)
{
throw new ServiceException("操作时间 必须填写");
}
var noneCashStatus = new[] { "新增待确认, 修改待确认, 审批中, 已拒绝, 平仓待复核, 行权待复核, 互换待复核, 提前终止拒绝" };
CreateTradePredicate(queryModel, out var noneCashPredicate, out var hasCashPredicate);
List<InnerDto> tempList = new List<InnerDto>();
DbContext.SetDebugLog();
if (noneCashPredicate != null)
{
var list = DbContext.trade.Where(noneCashPredicate)
.OrderBy(n => n.OptDate)
.Select(n => new InnerDto
{
td = n,
OptDate = n.OptDate
}).ToPagedList(new PagedQueryModel { GetTotal = false, PageSize = 10000 });
tempList.AddRange(list.Items);
}
if (hasCashPredicate != null)
{
var query = from tc in DbContext.trade_cash
join t in DbContext.trade.Where(hasCashPredicate) on tc.TradeId equals t.id
where tc.OptDate.Value > queryModel.OptDate && !tc.IsDeleted
&& tc.ValidState != ConsGlobal.InValid
orderby tc.OptDate.Value
select new InnerDto
{
td = t,
tc = tc.Action == "系统操作-期权费" ? null : new TradeCloseInfo
{
TcAction = tc.Action,
TcAmount = tc.Amount,
TcFinalPrice = tc.FinalPrice,
TcNotional = tc.Notional,
TcTradeAmount = tc.TradeAmount,
TcUnwindNotional = tc.UnwindNotional,
TcUnwindPercent = tc.UnwindPercentRate,
TcUnwindPrice = tc.UnwindPrice,
TcUnwindPricePercent = tc.UnwindPricePercentRate,
TcUnwindTradeAmount = tc.UnwindTradeAmount,
TcValueDate = tc.ValueDate,
TradeNumber = null,
TcTradePrice = 0,
WinLoss = 0
},
OptDate = tc.OptDate
};
var list = query.ToPagedList(new PagedQueryModel { GetTotal = false, PageSize = 10000 });
tempList.AddRange(list.Items);
}
var resultList = tempList.Select(n =>
{
var otcTrade = new TradeDetailQueryApiV2Result();
YLAutoMapper.Map<OtcTradeBase, OtcTradeBase>(n.td, otcTrade);
otcTrade.Notional = otcTrade.OriginalNotional ?? 0;
otcTrade.StockEqvNotional = otcTrade.OriginalStockEqvNotional ?? 0;
otcTrade.ClientNumber = ClientModule.ClientDataQueryService.GetClient(otcTrade.ClientId)?.Number;
if (n.tc != null)
{
var closeInfo = n.tc;
closeInfo.TradeNumber = n.td.TradeNumber;
closeInfo.TcTradePrice = (otcTrade.TradePrice ?? 0) * (closeInfo.TcUnwindPercent ?? 0) * ((otcTrade.BuySell == "卖出" || otcTrade.TradeType == "远期") ? 1 : -1);
closeInfo.WinLoss = (closeInfo.TcAmount ?? 0) + closeInfo.TcTradePrice;
otcTrade.CloseInfo = closeInfo;
}
otcTrade.OptDate = n.OptDate;
return otcTrade;
}).ToArray();
new TradeExtendService(this).SetTradeExtend(resultList, true);
return resultList;
}
/// <summary>
/// 根据查询参数拼接查询条件
/// </summary>
protected void CreateTradePredicate(TradeDetailQueryApiV2Request queryModel
, out Expression<Func<trade, bool>> noneCashPredicate
, out Expression<Func<trade, bool>> hasCashPredicate)
{
noneCashPredicate = hasCashPredicate = null;
var predicate = PredicateBuilder.Create<trade>(t => t.ValidState != ConsGlobal.InValid);
if (queryModel.IncludeGroupMain)
{
predicate = predicate.And(n => n.TradeType != "结构化交易" || n.IsGroup == 1);
}
else
{
predicate = predicate.And(n => n.TradeType != "结构化交易");
}
// 结构类型
if (queryModel.StructureTypes.HasNonEmptyItem())
{
predicate = predicate.And(d => queryModel.StructureTypes.Contains(d.TradeType)
|| queryModel.StructureTypes.Contains(d.StructureType));
}
//客户 优先使用客户编号
var clientIds = GetClientIdsByNumber(queryModel.ClientNumbers)
?? GetClientIdsByName(queryModel.ClientNames);
if (clientIds != null)
{
predicate = predicate.And(d => clientIds.Contains(d.ClientId));
}
var noneCashStatus = new[] { "新增待确认", "修改待确认", "审批中", "已拒绝", "平仓待复核", "行权待复核", "互换待复核", "提前终止拒绝" };
//交易状态:确认成交、新增待确认、已平仓、已到期。。。等等
if (queryModel.TradeStatus != null && queryModel.TradeStatus.Any())
{
noneCashStatus = noneCashStatus.Intersect(queryModel.TradeStatus).ToArray();
if (noneCashStatus.Any())
{
noneCashPredicate = predicate.And(d => noneCashStatus.Contains(d.TradeStatus));
}
var hasCashStatus = queryModel.TradeStatus.Except(noneCashStatus).ToArray();
if (hasCashStatus.Any())
{
hasCashPredicate = predicate.And(d => hasCashStatus.Contains(d.TradeStatus));
}
}
else
{
hasCashPredicate = predicate;
noneCashPredicate = predicate.And(d => noneCashStatus.Contains(d.TradeStatus));
}
if (noneCashPredicate != null)
{
noneCashPredicate = noneCashPredicate.And(n => n.OptDate.Value > queryModel.OptDate);
}
}
#region id再构建查询条件
/// <summary>
/// 根据交易对手方编号返回交易对手方ID
/// </summary>
/// <param name="clientNumbers">交易对手方编号</param>
private List<int> GetClientIdsByNumber(IEnumerable<string> clientNumbers)
{
if (!clientNumbers.HasNonEmptyItem())
{
return null;
}
using (var clientDbContext = DbContextFactory.GetClientDbContext(OptUser))
{
return clientDbContext.client.Where(x => clientNumbers.Contains(x.Number)).Select(x => x.id).ToList();
}
}
/// <summary>
/// 根据客户名称返回客户ID
/// </summary>
private List<int> GetClientIdsByName(IEnumerable<string> clientNames)
{
if (!clientNames.HasNonEmptyItem())
{
return null;
}
using (var clientDbContext = DbContextFactory.GetClientDbContext(OptUser))
{
return clientDbContext.client.Where(x => clientNames.Contains(x.Name)).Select(x => x.id).ToList();
}
}
#endregion
class InnerDto
{
public trade td { get; set; }
public TradeCloseInfo tc { get; set; }
public DateTime? OptDate { get; set; }
}
}
/// <summary>
/// api/v2/tradeDetailList
/// </summary>
public class TradeDetailQueryApiV2Result : OtcOptionTradeFull
{
public TradeCloseInfo CloseInfo { get; set; }
}
}
@@ -0,0 +1,43 @@
namespace YLErp.Modules.TradeModule.ApiModule
{
/// <summary>
/// 组合交易主交易了结请求
/// </summary>
public class TradeGroupCloseRequest
{
/// <summary>
/// 交易编号
/// </summary>
public string TradeNumber { get; set; }
/// <summary>
/// 要平仓的子交易编号集合
/// </summary>
public IEnumerable<string> SubTradeNumbers { get; set; }
/// <summary>
/// 了结方式
/// </summary>
public string UnwindType { get; set; }
/// <summary>
/// 了结日期
/// </summary>
public DateTime ValueDate { get; set; }
/// <summary>
/// 标的价格
/// </summary>
public double UnderlyingPrice { get; set; }
/// <summary>
/// 平仓数量/比例/名义本金
/// </summary>
public double UnwindAmount { get; set; }
/// <summary>
/// 百分比;名义本金;数量
/// </summary>
public string UnwindAmountFlag { get; set; }
}
}
@@ -0,0 +1,207 @@
using YLErp.DBModels.Converts;
using YLErp.Modules.TradeModule.DealModule;
namespace YLErp.Modules.TradeModule.ApiModule
{
/// <summary>
/// for api/v1/trade/group_options_close_start
/// </summary>
public class TradeGroupCloseService : YLBaseService
{
public TradeGroupCloseService(OptUserInfo userInfo) : base(userInfo)
{
}
/// <summary>
/// for api/v1/trade/group_options_close_start
/// </summary>
public void ExecuteCloseStart(TradeGroupCloseRequest req)
{
if (req is null)
{
throw new ArgumentNullException(nameof(req));
}
switch (req.UnwindType)
{
case "全部平仓":
case "部分平仓":
case "全部提前行权":
case "部分提前行权":
case "到期行权":
case "到期":
break;
default:
var message = string.IsNullOrWhiteSpace(req.UnwindType) ? "了结方式 必须填写" : "不支持的了结方式:" + req.UnwindType;
throw new ServiceException(message);
}
if (string.IsNullOrWhiteSpace(req.TradeNumber))
{
throw new ServiceException("主交易编号 必须填写");
}
var tradeNumbers = new List<string>()
{
req.TradeNumber
};
if (req.SubTradeNumbers != null && req.SubTradeNumbers.Any())
{
tradeNumbers.AddRange(req.SubTradeNumbers);
}
var tdList = DbContext.trade
.Where(n => tradeNumbers.Contains(n.TradeNumber))
.Select(n => new
{
n.id,
n.TradeNumber,
n.TradeType,
n.IsGroup,
n.IsUsePremiumRate,
n.BuySell,
n.Notional,
n.TradeAmount,
n.ParentTradeId,
n.ValidState,
n.TradeStatus
}).ToList();
var td = tdList.FirstOrDefault(n => n.TradeNumber == req.TradeNumber);
if (td == null)
{
throw new ServiceException("交易信息不存在:" + req.TradeNumber);
}
if (td.TradeType != "结构化交易" || td.IsGroup != 1)
{
throw new ServiceException("所选交易非组合交易主交易,不支持此API调用");
}
var tradeIds = tdList.Select(n => n.id).ToList();
if (tradeNumbers.Count > 1)
{
//缺失交易信息的交易编号
var missings = tradeNumbers.Where(tn => !tdList.Any(t => t.TradeNumber == tn)).ToArray();
if (missings.Any())
{
throw new ServiceException("交易信息不存在:" + string.Join(",", missings));
}
var errors = tdList.Select(n =>
{
if (n.ParentTradeId != td.id && n != td)
{
return $"交易编号:{n.TradeNumber},不属于同一组合;";
}
if (!ConsGlobal.IsValid(n.ValidState))
{
return $"交易编号:{n.TradeNumber},已被删除;";
}
if (n.TradeStatus != "确认成交")
{
return $"交易编号:{n.TradeNumber},,交易状态:{n.TradeStatus},确认成交状态下才可做了结操作;";
}
return null;
}).Where(n => n != null).ToArray();
if (errors.Any())
{
throw new ServiceException(string.Join(string.Empty, errors));
}
}
else
{
//补全子交易
var subIds = DbContext.trade.Where(n => n.ParentTradeId == td.id && n.IsGroup == 2 && n.ValidState != ConsGlobal.InValid && n.TradeStatus == "确认成交")
.Select(n => n.id).ToArray();
tradeIds.AddRange(subIds);
}
if (tradeIds.Count == 1)
{
throw new ServiceException("该分组交易没有可以了结操的子交易,不支持此API调用");
}
var tc = new trade_cash
{
id = 0,
TradeId = td.id,
ValueDate = req.ValueDate,
ExceciseType = null,
TradeType = BuySellConvert.GetClientBuySell(td.BuySell),
CallPut = null,
Strike = null,
Notional = td.Notional,
Amount = 0,
Action = req.UnwindType,
ValidState = null,
Status = null,
FinalPrice = req.UnderlyingPrice,
UnwindPrice = null,
UnwindVol = null,
VolType = null,
UnwindType = null,
UnwindNotional = null,
ExtraAmount = null,
SettleDate = null,
Comments = null,
ExerciseWay = null,
TradeAmount = td.TradeAmount,
UnwindTradeAmount = 0,
UnwindPercentRate = null,
UnwindPricePercentRate = null,
BarrierPrice = null,
HappenedDate = null,
ConfirmDate = System.DateTime.MinValue,
ParentTradeId = 0,
ParentTradeCashId = 0,
SpotPrice = null,
NotionalPercentRate = null,
TradePremium = 0,
IsDeleted = false,
AdvanceMoney = 0,
IsLastAction = false
};
if (td.IsUsePremiumRate == true)
{
if (req.UnwindAmountFlag == "百分比")
{
tc.UnwindPercentRate = req.UnwindAmount * 100;//要乘以100因为进入实际逻辑以后又会除以100
}
else if (req.UnwindAmountFlag == "名义本金")
{
tc.IsUnwindStockEqvNotional = true;
tc.UnwindStockEqvNotional = req.UnwindAmount;
}
else
{
throw new ServiceException("交易是以'名义本金方式'成交的,仅支持以'百分比'和'名义本金'方式平仓");
}
}
else
{
if (req.UnwindAmountFlag == "数量")
{
tc.UnwindTradeAmount = req.UnwindAmount;
}
else
{
throw new ServiceException("交易是以'数量方式'成交的,仅支持'数量'方式平仓");
}
}
new TradeUnwindService(this).SaveGroupTradeCash(new Model.SaveGroupTradeCashReq
{
trade_cash = tc,
tradeIds = tradeIds,
from_group_options_close_start_v1 = true
});
}
}
}
@@ -0,0 +1,8 @@
namespace YLErp.Modules.TradeModule.ApiModule
{
public class TradeSettleQueryModel
{
public string TradeNumber { get; set; }
public DateTime ValueDate { get; set; }
}
}