361 lines
15 KiB
C#
361 lines
15 KiB
C#
using System.Data;
|
|
using System.Linq.Expressions;
|
|
using System.Text.Json.Serialization;
|
|
using YLErp.Enums;
|
|
using YLErp.Office.ExcelModule;
|
|
|
|
namespace YLErp.Modules.TradeModule.SwapModule
|
|
{
|
|
public class SwapMultiCloseService : YLBaseService
|
|
{
|
|
public SwapMultiCloseService(OptUserInfo userInfo) : base(userInfo)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取分页数据(互换 -- 目前只有国君定制化的)
|
|
/// </summary>
|
|
public IPagedList<TradeSwapFlowMultiCloseResultModel> GetPagedDatas(TradeMultiCloseQueryModel queryModel)
|
|
{
|
|
if (queryModel is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(queryModel));
|
|
}
|
|
|
|
BuildPredicate(queryModel, out var tdPredicate, out var tcPredicate);
|
|
var basicQuery = DbContext.trade.Where(tdPredicate);
|
|
|
|
var query = from t in basicQuery.Where(tdPredicate)
|
|
join tc in DbContext.trade_cash.Where(tcPredicate) on t.id equals tc.TradeId
|
|
join optc in DbContext.trade_cash.Where(x => x.ValidState != "InValid" && !x.IsDeleted && x.Action == "系统操作-期权费") on t.id equals optc.TradeId
|
|
join sw in DbContext.trade_swap on t.id equals sw.TradeId
|
|
join tcsw in DbContext.trade_cash_swap on tc.id equals tcsw.TradeCashId
|
|
select new TradeSwapFlowMultiCloseResultModel
|
|
{
|
|
id = t.id,
|
|
TradeNumber = t.TradeNumber,
|
|
TraderName = t.TraderName,
|
|
AssetBookName = t.AssetBookName,
|
|
ClientName = t.ClientName,
|
|
TradeDate = t.TradeDate,
|
|
StartDate = t.StartDate,
|
|
ExerciseDate = t.ExerciseDate,
|
|
SettlementDate = t.SettlementDate,
|
|
CloseDate = tc.ValueDate,
|
|
OriginalNotional = t.OriginalNotional ?? 0,
|
|
Notional = tc.Notional - (tc.UnwindNotional ?? 0),
|
|
UnWindNotional = tc.UnwindNotional ?? 0,
|
|
UnderlyingCode = t.UnderlyingCode,
|
|
SpotPrice = t.SpotPrice,
|
|
TradeCommission = sw.GetTradePrice ?? (-sw.PayTradePrice) ?? 0,
|
|
//导入的期末价格使用的是UnwindPrice
|
|
UnwindPrice = tc.UnwindPrice ?? tc.FinalPrice ?? 0,
|
|
TradeCashId = tc.id,
|
|
CloseType = tc.Action,
|
|
Amount = tc.Amount,
|
|
RealizedPnl = tc.Amount + optc.Amount * (tc.UnwindPercentRate ?? 0),
|
|
QuoteRealizedPnl = (tc.QuoteAmount ?? tc.Amount) + (optc.QuoteAmount ?? optc.Amount) * (tc.UnwindPercentRate ?? 0),
|
|
OpenCurrencyRate = optc.CurrencyRate ?? 1,
|
|
CloseCurrencyRate = tc.CurrencyRate ?? 1,
|
|
trade_swap = sw
|
|
};
|
|
|
|
if (queryModel.UnWindTimes != null && queryModel.UnWindTimes >= 0)
|
|
{
|
|
var qgp = (from f in query
|
|
group f by f.id into fgp
|
|
where fgp.Count() == queryModel.UnWindTimes
|
|
select fgp.Key).ToList();
|
|
query = query.Where(q => qgp.Contains(q.id));
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(queryModel.UnWindType) && queryModel.UnWindType != "全部")
|
|
{
|
|
if (queryModel.UnWindType == "终止")
|
|
{
|
|
query = query.Where(x => x.CloseType == ClientCashInCashOut.系统操作_平仓费);
|
|
}
|
|
else if (queryModel.UnWindType == "到期")
|
|
{
|
|
query = query.Where(x => x.CloseType == ClientCashInCashOut.系统操作_互换 && x.CloseDate == x.ExerciseDate);
|
|
}
|
|
else if (queryModel.UnWindType == "互换")
|
|
{
|
|
query = query.Where(x => x.CloseType == ClientCashInCashOut.系统操作_互换 && x.CloseDate < x.ExerciseDate);
|
|
}
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(queryModel.SortExpression))
|
|
{
|
|
query = query.OrderByDescending(x => x.CloseDate).ThenBy(x => x.TradeCashId);
|
|
}
|
|
var pagedList = query.ToPagedList(queryModel);
|
|
|
|
TradeSwapFlowMultiCloseResultModel preData = null;
|
|
foreach (var data in pagedList)
|
|
{
|
|
var underlying = DataCacheModule.DataCacheManager.GetUnderlyingDataSource().GetData(data.UnderlyingCode);
|
|
underlying.Variety = DataCacheModule.DataCacheManager.GetVarietyDataSource().GetData(underlying.CommodityCode);
|
|
data.QuoteCurrency = underlying.Variety.QuoteCurrency ?? ConsGlobal.Currency.CNY;
|
|
data.CountRatio = underlying?.CountRatio ?? 1;
|
|
data.UnderlyingName = underlying?.UnderlyingName;
|
|
|
|
if (preData?.id == data.id)
|
|
{
|
|
data.CloseSeq = preData.CloseSeq + 1;
|
|
}
|
|
preData = data;
|
|
|
|
if (data.trade_swap.IsGetFloatingProfit)
|
|
{
|
|
data.trade_swap.GetOpenPrice = data.trade_swap.GetSpotPrice + (data.trade_swap.GetLongShort == "多头" ? 1 : -1) * ((data.trade_swap.PaySingleFee ?? 0) / underlying.ContractSize + (data.trade_swap.GetSpotPrice * data.trade_swap.PayUnAnnualRate ?? 0));
|
|
}
|
|
else
|
|
{
|
|
data.trade_swap.PayOpenPrice = data.trade_swap.PaySpotPrice + (data.trade_swap.PayLongShort == "多头" ? 1 : -1) * ((data.trade_swap.GetSingleFee ?? 0) / underlying.ContractSize + (data.trade_swap.PaySpotPrice * data.trade_swap.GetUnAnnualRate ?? 0));
|
|
}
|
|
data.OpenPrice = data.trade_swap.GetOpenPrice ?? data.trade_swap.PayOpenPrice ?? 0;
|
|
|
|
data.OriginalStockEqvNotional = data.OpenPrice * data.OriginalNotional * data.OpenCurrencyRate;
|
|
data.StockEqvNotional = data.OpenPrice * data.Notional * data.OpenCurrencyRate;
|
|
data.CloseStockEqvNotional = data.OpenPrice * (data.UnWindNotional ?? 0) * data.OpenCurrencyRate;
|
|
|
|
var details = DbContext.trade_cash_detail.Where(x => x.TradeCashId == data.TradeCashId);
|
|
data.FixedIncome = details.Where(x => x.TradeCashType == TradeCashTypeEnum.利息.ToString()).Sum(x => x.Amount);
|
|
data.UnwindFee = details.Where(x => x.TradeCashType == TradeCashTypeEnum.了结手续费.ToString()).Sum(x => x.QuoteAmount);
|
|
data.FloatIncome = data.Amount - data.FixedIncome;
|
|
|
|
if (data.trade_swap.IsGetFloatingProfit)
|
|
{
|
|
data.ClosePrice = data.UnwindPrice + ((data.trade_swap.GetLongShort == "多头" ? -1 : 1) * (-data.UnwindFee ?? 0) / data.UnWindNotional).Normalize();
|
|
}
|
|
else
|
|
{
|
|
data.ClosePrice = data.UnwindPrice + ((data.trade_swap.PayLongShort == "多头" ? -1 : 1) * (data.UnwindFee ?? 0) / data.UnWindNotional).Normalize();
|
|
}
|
|
|
|
if (data.CloseType == "系统操作-互换")
|
|
{
|
|
if (data.CloseDate == data.ExerciseDate)
|
|
{
|
|
data.CloseType = "到期";
|
|
}
|
|
else
|
|
{
|
|
data.CloseType = "互换";
|
|
}
|
|
}
|
|
else if (data.CloseType == "系统操作-平仓费")
|
|
{
|
|
data.CloseType = "终止";
|
|
}
|
|
}
|
|
|
|
return pagedList;
|
|
}
|
|
|
|
private void BuildPredicate(TradeMultiCloseQueryModel queryModel, out Expression<Func<trade, bool>> tdPredicate, out Expression<Func<trade_cash, bool>> tcPredicate)
|
|
{
|
|
tdPredicate = PredicateBuilder.Create<trade>(t => t.ValidState != ConsGlobal.InValid && t.TradeType == "收益互换");
|
|
|
|
if (queryModel.UserAssets != null && queryModel.UserClients != null)
|
|
{
|
|
tdPredicate = tdPredicate.And(n => queryModel.UserAssets.Contains(n.AssetId) || queryModel.UserClients.Contains(n.ClientId));
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(queryModel.TradeNumber))
|
|
{
|
|
var TradeNumber = queryModel.TradeNumber.Trim();
|
|
tdPredicate = tdPredicate.And(n => n.TradeNumber.Contains(TradeNumber));
|
|
}
|
|
|
|
if (!string.IsNullOrEmpty(queryModel.TraderNames))
|
|
{
|
|
tdPredicate = tdPredicate.And(d => queryModel.TraderNamesList.Contains(d.TraderId));
|
|
}
|
|
|
|
if (queryModel.AssetIdList.Any())
|
|
{
|
|
tdPredicate = tdPredicate.And(d => queryModel.AssetIdList.Contains(d.AssetId));
|
|
}
|
|
|
|
if (queryModel.ClientIdList.Any())
|
|
{
|
|
tdPredicate = tdPredicate.And(n => queryModel.ClientIdList.Contains(n.ClientId));
|
|
}
|
|
|
|
if (queryModel.TradeDateStart != null)
|
|
{
|
|
tdPredicate = tdPredicate.And(n => n.TradeDate >= queryModel.TradeDateStart.Value);
|
|
}
|
|
if (queryModel.TradeDateEnd != null)
|
|
{
|
|
tdPredicate = tdPredicate.And(n => n.TradeDate <= queryModel.TradeDateEnd.Value);
|
|
}
|
|
|
|
if (queryModel.ExerciseDateStart != null)
|
|
{
|
|
tdPredicate = tdPredicate.And(n => n.ExerciseDate >= queryModel.ExerciseDateStart.Value);
|
|
}
|
|
if (queryModel.ExerciseDateEnd != null)
|
|
{
|
|
tdPredicate = tdPredicate.And(n => n.ExerciseDate <= queryModel.ExerciseDateEnd.Value);
|
|
}
|
|
|
|
if (queryModel.AssetUnitIds != null && queryModel.AssetUnitIds.Any(a => a > 0))
|
|
{
|
|
tdPredicate = tdPredicate.And(n => queryModel.AssetUnitIds.Contains(n.AssetId));
|
|
}
|
|
|
|
var underlyids = queryModel.UnderlyingIdList.ToList();
|
|
if (!string.IsNullOrWhiteSpace(queryModel.UnderlyingName))
|
|
{
|
|
var _underlyids = DbContext.underlying_manager.Where(x => x.UnderlyingName.Contains(queryModel.UnderlyingName)).Select(x => x.id).ToHashSet();
|
|
if (underlyids.Count() > 0)
|
|
{
|
|
underlyids = underlyids.Intersect(_underlyids).Distinct().ToList();
|
|
}
|
|
else
|
|
{
|
|
underlyids = _underlyids.ToList();
|
|
}
|
|
}
|
|
if (queryModel.UnderlyingIdList.Any(n => n > 0) || !string.IsNullOrWhiteSpace(queryModel.UnderlyingName))
|
|
{
|
|
tdPredicate = tdPredicate.And(n => underlyids.Contains(n.UnderlyingId));
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(queryModel.TradeStatus))
|
|
{
|
|
var statuses = queryModel.TradeStatus.Split(',').ToList();
|
|
tdPredicate = tdPredicate.And(n => statuses.Contains(n.TradeStatus));
|
|
}
|
|
|
|
tcPredicate = PredicateBuilder.Create<trade_cash>(tc => tc.ValidState != "InValid" && !tc.IsDeleted && (tc.Action == "系统操作-行权费" || tc.Action == "系统操作-平仓费" || tc.Action == "系统操作-互换"));
|
|
|
|
if (queryModel.UnwindDateStart != null)
|
|
{
|
|
tcPredicate = tcPredicate.And(n => n.ValueDate >= queryModel.UnwindDateStart.Value);
|
|
}
|
|
if (queryModel.UnwindDateEnd != null)
|
|
{
|
|
tcPredicate = tcPredicate.And(n => n.ValueDate <= queryModel.UnwindDateEnd.Value);
|
|
}
|
|
|
|
if (queryModel.TradeCashIdList.Any())
|
|
{
|
|
tcPredicate = tcPredicate.And(x => queryModel.TradeCashIdList.Contains(x.id));
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 导出所有字段
|
|
/// </summary>
|
|
public byte[] ExportAllFieldsToExcel(TradeMultiCloseQueryModel queryModel)
|
|
{
|
|
var list = GetPagedDatas(queryModel);
|
|
var results = new List<Dictionary<string, string>>(list.Count());
|
|
var templateFile = OtcAppContext.MapPath("~/App_Docs/导出模板/国君互换了结导出模板.xlsx");
|
|
return ExcelGenerator.UseTemplateGenerator(templateFile).AddVariable(new { list = list }).GenerateBytes();
|
|
}
|
|
}
|
|
|
|
public class TradeSwapFlowMultiCloseResultModel : OtcTradeBase
|
|
{
|
|
/// <summary>
|
|
/// 了结日期
|
|
/// </summary>
|
|
public DateTime? CloseDate { get; set; }
|
|
|
|
/// <summary>
|
|
/// 了结序号
|
|
/// </summary>
|
|
public int CloseSeq { get; set; } = 1;
|
|
|
|
/// <summary>
|
|
/// 了结方式
|
|
/// </summary>
|
|
public string CloseType { get; set; }
|
|
|
|
/// <summary>
|
|
/// 互换类型 -- 固定为“普通”
|
|
/// </summary>
|
|
public string SwapType { get; set; } = "普通";
|
|
|
|
/// <summary>
|
|
/// 了结名义本金
|
|
/// </summary>
|
|
public double CloseStockEqvNotional { get; set; }
|
|
|
|
/// <summary>
|
|
/// 开仓标的价格(费后)
|
|
/// </summary>
|
|
public double OpenPrice { get; set; }
|
|
|
|
/// <summary>
|
|
/// 了结标的价格(费后)
|
|
/// </summary>
|
|
public double ClosePrice { get; set; }
|
|
|
|
/// <summary>
|
|
/// 平仓费用
|
|
/// </summary>
|
|
public double? UnwindFee { get; set; }
|
|
|
|
/// <summary>
|
|
/// 了结标的价格
|
|
/// </summary>
|
|
public double UnwindPrice { get; set; }
|
|
|
|
/// <summary>
|
|
/// 浮动收益
|
|
/// </summary>
|
|
public double? FloatIncome { get; set; }
|
|
|
|
/// <summary>
|
|
/// 固定收益
|
|
/// </summary>
|
|
public double? FixedIncome { get; set; }
|
|
|
|
/// <summary>
|
|
/// 平仓总额
|
|
/// </summary>
|
|
public double? Amount { get; set; }
|
|
|
|
/// <summary>
|
|
/// 实现盈亏
|
|
/// </summary>
|
|
public double RealizedPnl { get; set; }
|
|
|
|
/// <summary>
|
|
/// 实现盈亏(结算)
|
|
/// </summary>
|
|
public double QuoteRealizedPnl { get; set; }
|
|
|
|
[JsonIgnore]
|
|
public int TradeCashId { get; set; }
|
|
|
|
/// <summary>
|
|
/// 成交手续费(了结部分所占的开仓总费用)
|
|
/// </summary>
|
|
public double TradeCommission { get; set; }
|
|
|
|
/// <summary>
|
|
/// 标的名称
|
|
/// </summary>
|
|
public string UnderlyingName { get; set; }
|
|
|
|
/// <summary>
|
|
/// 开仓汇率
|
|
/// </summary>
|
|
public double OpenCurrencyRate { get; set; }
|
|
|
|
/// <summary>
|
|
/// 结算汇率
|
|
/// </summary>
|
|
public double CloseCurrencyRate { get; set; }
|
|
|
|
public trade_swap trade_swap { get; set; }
|
|
}
|
|
}
|