从山证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,360 @@
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; }
}
}
@@ -0,0 +1,406 @@
using BaseOUDAL;
using YLErp.BLL;
using YLErp.Model;
using YLErp.QdpModule;
namespace YLErp.Modules.TradeModule.SwapModule
{
public class SwapTradeFlowCheckService : TradeServiceBase
{
public SwapTradeFlowCheckService(OptUserInfo userInfo) : base(userInfo)
{
}
public SwapTradeFlowCheckService(YLBaseService baseService) : base(baseService)
{
}
public void CheckSwapTradeFlow(string tradeNumber)
{
var valueDateConst = valuedateBLL.ValueDate;
var flowsAll = DbContext.trade_swap_flow.Where(x => x.TradeDate == valueDateConst).ToList();
var flows = flowsAll.Where(x => x.Status != "已完成").ToList();
var positionTrades = (from td in DbContext.trade.Where(x => x.TradeStatus == "确认成交" && x.TradeType == "收益互换" && x.ValidState != "InValid")
join ts in DbContext.trade_swap.Where(x => x.SwapType == "多空组合")
on td.id equals ts.TradeId
select new { td, ts }).ToList();
var existList = DbContext.trade_swap_flow_check_result.ToList();
if (!string.IsNullOrWhiteSpace(tradeNumber))
{
positionTrades = positionTrades.Where(x => x.td.TradeNumber == tradeNumber).ToList();
if (!positionTrades.Any())
{
throw new Exception($"未找到交易编号{tradeNumber}对应的多空组合持仓交易");
}
var tradeIds = positionTrades.Select(x => x.td.id).ToList();
existList = existList.Where(x => tradeIds.Contains(x.TradeId)).ToList();
}
if (existList.Any())
{
DbContext.trade_swap_flow_check_result.RemoveRange(existList);
}
positionTrades.ForEach(x =>
{
//创建一笔默认为成功的result
var result = new trade_swap_flow_check_result()
{
IsSuccess = true,
TradeId = x.td.id,
OptId = UserId,
OptName = UserName,
OptDate = DateTime.Now
};
//当天开仓的交易
if (x.ts.OriginalTradeId == null && x.td.TradeDate == valueDateConst)
{
if (!flowsAll.Any(y => y.TradeNumber == x.td.TradeNumber))
{
//验证失败
result.IsSuccess = false;
result.Detail += "该新开仓的多空组合交易未找到对应的操作流水;<br>";
}
else
{
var flowsThis = flows.Where(y => y.TradeNumber == x.td.TradeNumber).ToList();
//开始验证逻辑
DoCheck(x.td, flowsThis, result);
}
}
//前一天持仓的交易
else
{
var originalTradeNumber = x.td.TradeNumber;
if (x.ts.OriginalTradeId != null)
{
originalTradeNumber = DbContext.trade.Find(x.ts.OriginalTradeId).TradeNumber;
}
var flowsThis = flows.Where(y => y.TradeNumber == originalTradeNumber).ToList();
//开始验证逻辑
DoCheck(x.td, flowsThis, result);
}
SaveCheckResult(result);
});
}
public string CheckSwapTradeGroup(string tradeNumber)
{
var valueDateConst = valuedateBLL.ValueDate;
var flowsAll = DbContext.trade_swap_flow.Where(x => x.TradeDate == valueDateConst).ToList();
var flows = flowsAll.Where(x => x.Status != "已完成").ToList();
var positionTrade = (from td in DbContext.trade.Where(x => x.TradeStatus == "确认成交" && x.TradeNumber == tradeNumber && x.TradeType == "收益互换" && x.ValidState != "InValid")
join ts in DbContext.trade_swap.Where(x => x.SwapType == "多空组合")
on td.id equals ts.TradeId
select new { td, ts }).FirstOrDefault();
if (positionTrade == null)
{
throw new Exception($"未找到交易编号{tradeNumber}对应的多空组合持仓交易");
}
else
{
var existList = DbContext.trade_swap_flow_check_result.Where(x => x.TradeId == positionTrade.td.id).ToList();
if (existList.Any())
{
DbContext.trade_swap_flow_check_result.RemoveRange(existList);
}
}
//创建一笔默认为成功的result
var result = new trade_swap_flow_check_result()
{
IsSuccess = true,
TradeId = positionTrade.td.id,
OptId = UserId,
OptName = UserName,
OptDate = DateTime.Now
};
//当天开仓的交易
if (positionTrade.ts.OriginalTradeId == null && positionTrade.td.TradeDate == valueDateConst)
{
if (!flowsAll.Any(y => y.TradeNumber == positionTrade.td.TradeNumber))
{
//验证失败
result.IsSuccess = false;
result.Detail += "该新开仓的多空组合交易未找到对应的操作流水;<br>";
}
else
{
var flowsThis = flows.Where(y => y.TradeNumber == positionTrade.td.TradeNumber).ToList();
//开始验证逻辑
DoCheck(positionTrade.td, flowsThis, result);
}
}
//前一天持仓的交易
else
{
var originalTradeNumber = positionTrade.td.TradeNumber;
if (positionTrade.ts.OriginalTradeId != null)
{
originalTradeNumber = DbContext.trade.Find(positionTrade.ts.OriginalTradeId).TradeNumber;
}
var flowsThis = flows.Where(y => y.TradeNumber == originalTradeNumber).ToList();
//开始验证逻辑
DoCheck(positionTrade.td, flowsThis, result);
}
SaveCheckResult(result);
return string.IsNullOrEmpty(result.Detail) ? "检测成功" : result.Detail;
}
public SearchListResult<TradeFlowCheckResultResponse> SearchFlowCheckResultList(TradeFlowCheckResultReq req)
{
var query = from result in DbContext.trade_swap_flow_check_result
join trade in DbContext.trade
on result.TradeId equals trade.id
select new TradeFlowCheckResultResponse() { trade = trade, trade_swap_flow_check_result = result };
if (!string.IsNullOrEmpty(req.TradeNumber))
{
query = query.Where(d => d.trade.TradeNumber == req.TradeNumber);
}
if (req.ClientIds != null && req.ClientIds.Any())
{
query = query.Where(d => req.ClientIds.Contains(d.trade.ClientId));
}
if (req.IsSuccessList != null && req.IsSuccessList.Any())
{
query = query.Where(d => req.IsSuccessList.Contains(d.trade_swap_flow_check_result.IsSuccess));
}
if (string.IsNullOrEmpty(req.sidx))
{
req.sidx = "trade_swap_flow_check_result.id";
req.sord = "asc";
}
var retListResult = query.ToSearchList(req);
return retListResult;
}
private void DoCheck(trade trade, List<trade_swap_flow> flows, trade_swap_flow_check_result result)
{
var valueDateConst = valuedateBLL.ValueDate;
List<trade> childTrades = new List<trade>();
var children = (from td in DbContext.trade.Where(x => x.ParentTradeId == trade.id && x.ValidState != "InValid")
join ts in DbContext.trade_swap
on td.id equals ts.TradeId
join un in DbContext.underlying_manager
on td.UnderlyingId equals un.id
select new { td.UnderlyingCode, td.Notional, ts.IsGetFloatingProfit, ts.GetLongShort, ts.PayLongShort, un.Price }).ToList();
if (children.Any())
{
children.ForEach(x =>
{
var child = new trade()
{
UnderlyingCode = x.UnderlyingCode,
SpotPrice = x.Price,
Notional = x.Notional,
BuySell = x.IsGetFloatingProfit ? x.GetLongShort : x.PayLongShort
};
childTrades.Add(child);
});
}
childTrades.ForEach(x =>
{
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(x.UnderlyingCode);
var unFlows = flows.Where(y => y.UnderlyingCode == x.UnderlyingCode);
var notional = x.Notional * (x.BuySell == "多头" ? 1 : -1) + unFlows.Sum(y => y.Lots * um.ContractSize * (y.BuySell == "买入" || y.BuySell == "B" ? 1 : -1));
x.Notional = Math.Abs(notional);
x.BuySell = notional > 0 ? "多头" : "空头";
});
var childTradesUnderlyingCode = childTrades.Select(x => x.UnderlyingCode).ToList();
var addFlows = flows.Where(x => !childTradesUnderlyingCode.Contains(x.UnderlyingCode));
if (addFlows.Any())
{
var addUnderlyingCodes = addFlows.Select(x => x.UnderlyingCode).Distinct().ToList();
addUnderlyingCodes.ForEach(x =>
{
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(x);
var unFlows = addFlows.Where(y => y.UnderlyingCode == x);
var notional = unFlows.Sum(y => y.Lots * um.ContractSize * (y.BuySell == "买入" || y.BuySell == "B" ? 1 : -1));
if (notional != 0)
{
//var spotPrice = Math.Abs(unFlows.Sum(y => (y.SpotPrice ?? 0) * y.Lots * (y.BuySell == "买入" || y.BuySell == "B" ? 1 : -1)) / unFlows.Sum(y => y.Lots));
var child = new trade()
{
UnderlyingCode = x,
SpotPrice = um.Price,
Notional = Math.Abs(notional),
BuySell = notional > 0 ? "多头" : "空头"
};
childTrades.Add(child);
}
});
}
//验证多头或空头挂钩标的数量不少于50只
var countLong = childTrades.Where(x => x.BuySell == "多头").Select(x => x.UnderlyingCode).Distinct().Count();
var countShort = childTrades.Where(x => x.BuySell == "空头").Select(x => x.UnderlyingCode).Distinct().Count();
if (countLong < 50 && countShort < 50)
{
//验证失败
result.IsSuccess = false;
result.Detail += $"多头挂钩标的数量【{countLong}】和空头挂钩标的数量【{countShort}】均少于50只;<br>";
}
var buyStockEqvNotional = childTrades.Sum(x => x.Notional * (x.SpotPrice ?? 0) * (x.BuySell == "多头" ? 1 : 0));
var sellStockEqvNotional = childTrades.Sum(x => x.Notional * (x.SpotPrice ?? 0) * (x.BuySell == "空头" ? 1 : 0));
if (buyStockEqvNotional == 0 || sellStockEqvNotional == 0)
{
//验证失败
result.IsSuccess = false;
result.Detail += $"多头收益互换名义本金与空头收益互换名义本金的比例不低于80%且不高于120%,多头名义本金[{buyStockEqvNotional}],空头名义本金[{sellStockEqvNotional}];<br>";
}
else
{
//验证 多头收益互换名义本金与空头收益互换名义本金的比例不低于80%且不高于120%
var rateTotal = buyStockEqvNotional / sellStockEqvNotional;
if (rateTotal > 1.2 || rateTotal < 0.8)
{
//验证失败
result.IsSuccess = false;
result.Detail += $"多头收益互换名义本金与空头收益互换名义本金的比例不低于80%且不高于120%,多头名义本金[{buyStockEqvNotional}],空头名义本金[{sellStockEqvNotional}];<br>";
}
}
//验证单一股票对应的合约名义本金占多方或空方股票对应的合约名义本金的比例不高于5%
childTrades.ForEach(x =>
{
var stockEqvNotional = (x.SpotPrice ?? 0) * x.Notional;
var totalStockEqvNotional = (x.BuySell == "多头" ? buyStockEqvNotional : sellStockEqvNotional);
var rate = stockEqvNotional / totalStockEqvNotional;
if (rate > 0.05)
{
//验证失败
result.IsSuccess = false;
result.Detail += $"单一股票对应的合约[{x.UnderlyingCode}]名义本金[{stockEqvNotional}]占多方或空方股票对应的合约名义本金[{totalStockEqvNotional}]的比例不高于5%;<br>";
}
});
var underlyingCodes = childTrades.Select(x => x.UnderlyingCode).ToList();
var startDate = valueDateConst.AddYears(-1);
var eodStockPricesDic = DbContext.eod_stock_price.Where(x => x.ValueDate >= startDate && x.ValueDate < valueDateConst && underlyingCodes.Contains(x.UnderlyingCode)).ToDictionary(x => new { x.ValueDate, x.UnderlyingCode }, x => x.ClosePrice);
var eodCommodityFuturePricesDic = DbContext.eod_commodity_future_price.Where(x => x.ValueDate >= startDate && x.ValueDate < valueDateConst && underlyingCodes.Contains(x.UnderlyingCode)).ToDictionary(x => new { x.ValueDate, x.UnderlyingCode }, x => x.ClosePrice);
List<TimeXY> list = new List<TimeXY>();
for (var time = startDate; time < valueDateConst;)
{
if (!QdpCalendarHelper.IsHoliday(time))
{
List<trade> timeChildTrades = new List<trade>();
childTrades.ForEach(x =>
{
if (eodStockPricesDic.ContainsKey(new { ValueDate = time, x.UnderlyingCode }))
{
timeChildTrades.Add(new trade()
{
UnderlyingCode = x.UnderlyingCode,
SpotPrice = eodStockPricesDic[new { ValueDate = time, x.UnderlyingCode }],
Notional = x.Notional,
BuySell = x.BuySell
});
}
else if (eodCommodityFuturePricesDic.ContainsKey(new { ValueDate = time, x.UnderlyingCode }))
{
timeChildTrades.Add(new trade()
{
UnderlyingCode = x.UnderlyingCode,
SpotPrice = eodCommodityFuturePricesDic[new { ValueDate = time, x.UnderlyingCode }],
Notional = x.Notional,
BuySell = x.BuySell
});
}
});
var buyChildTrades = timeChildTrades.Where(x => x.BuySell == "多头").ToList();
var sellChildTrades = timeChildTrades.Where(x => x.BuySell == "空头").ToList();
var item = new TimeXY()
{
Time = time,
Px = buyChildTrades.Sum(x => (x.SpotPrice ?? 0) * x.Notional) / buyChildTrades.Sum(x => x.Notional),
Py = sellChildTrades.Sum(x => (x.SpotPrice ?? 0) * x.Notional) / sellChildTrades.Sum(x => x.Notional),
};
list.Add(item);
}
time = time.AddDays(1);
}
list = list.OrderBy(x => x.Time).ToList();
var n = list.Count;
var index = 0;
//价格变化率只有n-1组
foreach (var item in list)
{
index++;
if (index < n)
{
item.x = list[index].Px / item.Px - 1;
item.y = list[index].Py / item.Py - 1;
}
}
var averageX = list.Sum(x => x.x) / (n - 1);
var averageY = list.Sum(x => x.y) / (n - 1);
var varX = list.Sum(x => Math.Pow(x.x - averageX, 2)) / ((n - 1) - 1);
var varY = list.Sum(x => Math.Pow(x.y - averageY, 2)) / ((n - 1) - 1);
var covXY = list.Sum(x => (x.x - averageX) * (x.y - averageY)) / ((n - 1) - 1);
var relation = covXY / Math.Sqrt(varX * varY);
if (relation < 0.8)
{
//验证失败
result.IsSuccess = false;
result.Detail += $"多头与空头收益互换挂钩标的的过去一年相关系数[{relation}]低于80%;<br>";
}
}
private void SaveCheckResult(trade_swap_flow_check_result result)
{
var existList = DbContext.trade_swap_flow_check_result.Where(x => x.TradeId == result.TradeId);
if (existList.Any())
{
DbContext.trade_swap_flow_check_result.RemoveRange(existList);
}
DbContext.trade_swap_flow_check_result.Add(result);
DbContext.SaveChanges();
}
}
public class TimeXY
{
public DateTime Time { get; set; }
public double Px { get; set; }
public double x { get; set; }
public double Py { get; set; }
public double y { get; set; }
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,889 @@
using BaseOUDAL;
using System.Data;
using YLErp.BLL;
using YLErp.Commons;
using YLErp.DBModels.Consts;
using YLErp.DBModels.Enums;
using YLErp.Enums;
using YLErp.Model.Enum;
using YLErp.Modules.CalculationModule;
namespace YLErp.Modules.TradeModule.SwapModule
{
public class SwapTradeFlowMoreImportService : TradeServiceBase
{
public SwapTradeFlowMoreImportService(OptUserInfo userInfo) : base(userInfo)
{
}
public SwapTradeFlowMoreImportService(YLBaseService baseService) : base(baseService)
{
}
/// <summary>
/// 导入交易
/// </summary>
/// <param name="streamIn"></param>
/// <param name="totalNum">当前文件中的目标期权总条数</param>
/// <param name="successNum">成功入库的数量</param>
public void ImportSwapTradeFlowFromExcel(Stream streamIn, out int totalNum, out int successNum)
{
totalNum = 0;
successNum = 0;
var rowIndex = 1;
try
{
var ds = Office.ExcelHelper.ReadExcelAsDataSet(streamIn, new[] { 0 }, 1);
if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 1)
{
throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" };
}
var table = ds.Tables[0];
var reader = new DataRowReader(table);
totalNum = table.Rows.Count;
using (var trans = BeginTransaction())
{
foreach (var row in table.Rows.Cast<DataRow>())
{
rowIndex++;
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
{
totalNum--;
continue;
}
reader.SetDataRow(row);
//映射导入数据到交易对象
var tradeFlow = MapSwapTrade(reader);
successNum++;
}
trans.Commit();
}
//generateSettleDocument(trade_Cashes);
//生成确认书
//new ConfirmationGenerateService(this).Generate(tradeIds, "PDF");
}
catch (ServiceException se)
{
if (se.Tag != null)
{
throw;
}
throw new ServiceException($"第{rowIndex}行,{se.Message}");
}
catch (Exception ex)
{
LogFactory.GetLogger("导入互换交易").Error(ex);
throw new ServiceException($"第{rowIndex}行,发生错误:{ex.Message}", ex);
}
}
private trade_swap_flow_more MapSwapTrade(DataRowReader reader)
{
var swapFlow = new trade_swap_flow_more();
swapFlow.ClientNumber = reader.GetString("客户编号", false);
swapFlow.ClientName = reader.GetString("客户名称", false);
swapFlow.UnderlyingCode = reader.GetString("标的代码", false);
swapFlow.UnderlyingName = reader.GetString("标的名称", false);
swapFlow.TraderName = reader.GetString("交易员", true);
swapFlow.AssetBookName = reader.GetString("簿记账户", true);
swapFlow.Notional = reader.GetDouble("成交数量", true) ?? 0;
swapFlow.BuySell = reader.GetString("交易方向", true);
swapFlow.TradeNumber = reader.GetString("交易编号", true);
swapFlow.TradeDate = reader.GetDate("开始日期", true);
swapFlow.ExerciseDate = reader.GetDate("到期日期", true);
swapFlow.Price = reader.GetDouble("期初标的价格", true) ?? 0;
swapFlow.CurrencyRate = reader.GetDouble("汇率", false) ?? 1;
swapFlow.AnnualRate = reader.GetDouble("利率", false);
swapFlow.TotalFee = reader.GetDouble("手续费", false);
swapFlow.MargeRate = reader.GetDouble("预付金率", false);
if (swapFlow.BuySell == "平仓")
{
swapFlow.UnwindDate = reader.GetDate("平仓日期", true);
swapFlow.UnwindPrice = reader.GetDouble("平仓价格", false);
swapFlow.UnwindNotional = reader.GetDouble("平仓数量", true) ?? 0;
swapFlow.FixedIncome = reader.GetDouble("固定收益", false);
swapFlow.Amount = reader.GetDouble("实现盈亏", false);
}
CheckAssignmentSwapTradeFlow(swapFlow);
swapFlow.OptId = UserId;
swapFlow.OptName = UserName;
swapFlow.OptDate = DateTime.Now;
DbContext.trade_swap_flow_more.Add(swapFlow);
DbContext.SaveChanges();
return swapFlow;
}
private void CheckNotNullSwapTradeFlow(TradeSwapFlowRequestModel model)
{
if (string.IsNullOrWhiteSpace(model.TraderName))
{
throw new ServiceException($"交易员不能为空");
}
if (string.IsNullOrWhiteSpace(model.AssetBookName))
{
throw new ServiceException($"簿记账户不能为空");
}
if (string.IsNullOrWhiteSpace(model.BuySell))
{
throw new ServiceException($"交易方向不能为空");
}
if (string.IsNullOrWhiteSpace(model.TradeNumber))
{
throw new ServiceException($"交易编号不能为空");
}
if (model.Notional == 0)
{
throw new ServiceException($"成交数量不能为0");
}
if (!model.TradeDate.HasValue)
{
throw new ServiceException($"开始日期不能为空");
}
if (!model.ExerciseDate.HasValue)
{
throw new ServiceException($"到期日期不能为空");
}
if (!model.OpenPrice.HasValue)
{
throw new ServiceException($"标的价格不能为空");
}
if (model.BuySell == "平仓")
{
if (!model.UnwindDate.HasValue)
{
throw new ServiceException($"平仓日期不能为空");
}
if (!model.UnwindPrice.HasValue)
{
throw new ServiceException($"平仓价格不能为空");
}
if (!model.UnwindNotional.HasValue)
{
throw new ServiceException($"平仓数量不能为空");
}
}
}
private void CheckAssignmentSwapTradeFlow(trade_swap_flow_more model)
{
string clientNumber = model.ClientNumber;
string clientName = model.ClientName;
if (!string.IsNullOrWhiteSpace(clientNumber))
{
var client = DataCacheProvider.GetClientDataSource().AsQueryable().FirstOrDefault(n => clientNumber.Equals(n.Number, StringComparison.OrdinalIgnoreCase));
if (client == null)
{
throw new ServiceException($"该客户编号[{clientNumber}]在系统中不存在");
}
model.ClientNumber = client.Number;
model.ClientId = client.id;
}
else if (!string.IsNullOrWhiteSpace(clientName))
{
var client = DataCacheProvider.GetClientDataSource().AsQueryable().FirstOrDefault(n => clientName.Equals(n.Name, StringComparison.OrdinalIgnoreCase));
if (client == null)
{
throw new ServiceException($"该客户名称[{clientName}]在系统中不存在");
}
model.ClientNumber = client.Number;
model.ClientId = client.id;
}
else
{
throw new ServiceException($"客户编号和客户名称不能同时为空");
}
string underlyingCode = model.UnderlyingCode;
string underlyingName = model.UnderlyingName;
if (!string.IsNullOrWhiteSpace(underlyingCode))
{
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(underlyingCode);
if (underlying == null)
{
throw new ServiceException($"该标的代码[{underlyingCode}]在系统中不存在");
}
model.UnderlyingCode = underlying.UnderlyingCode;
}
else if (!string.IsNullOrWhiteSpace(underlyingName))
{
var underlying = DataCacheProvider.GetUnderlyingDataSource().AsQueryable().FirstOrDefault(n => underlyingName.Equals(n.UnderlyingName, StringComparison.OrdinalIgnoreCase));
if (underlying == null)
{
throw new ServiceException($"该标的名称[{underlyingName}]在系统中不存在");
}
model.UnderlyingCode = underlying.UnderlyingCode;
}
else
{
throw new ServiceException($"标的代码和标的名称不能同时为空");
}
string traderName = model.TraderName;
var traders = UserBLL.GetUsersByPosition().FirstOrDefault(x => x.Name == traderName);
if (traders == null)
{
throw new ServiceException($"该交易员[{traderName}]在系统中不存在");
}
model.TraderId = traders.Id;
model.TraderName = traders.Name;
string assetBookName = model.AssetBookName;
var assetUnit = DataCacheProvider.GetAssetUnitDataSource().AsQueryable().FirstOrDefault(x => x.Name == assetBookName);
if (assetUnit == null)
{
throw new ServiceException($"该簿记账户[{assetBookName}]在系统中不存在");
}
else
{
if (!("," + assetUnit.TraderIds + ",").Contains("," + model.TraderId + ","))
{
throw new ServiceException($"该交易员[{model.TraderName}]不在簿记账户[{assetBookName}]中");
}
}
model.AssetId = assetUnit.id;
model.AssetBookName = assetUnit.Name;
double notional = model.Notional;
if (notional == 0)
{
throw new ServiceException($"成交数量不能为0");
}
string longShort = notional > 0 ? "多头" : "空头";
model.LongShort = longShort;
model.Notional = notional;
if (model.BuySell == "开仓")
{
if (DbContext.trade.Where(x => x.TradeNumber == model.TradeNumber && x.ValidState != "InValid").Any())
{
throw new ServiceException($"该交易已存在,编号[{model.TradeNumber}]");
}
if (DbContext.trade_swap_flow_more.Where(x => x.TradeNumber == model.TradeNumber && !x.IsDelete).Any())
{
throw new ServiceException($"开仓流水已存在该交易编号,编号[{model.TradeNumber}]");
}
}
if (model.BuySell == "平仓")
{
if (model.UnwindNotional == 0)
{
throw new ServiceException($"平仓数量不能为0");
}
}
}
/// <summary>
/// 互换流水api导入
/// </summary>
/// <param name="reader"></param>
/// <returns></returns>
/// <exception cref="ServiceException"></exception>
public trade_swap_flow_more SwapTradeFlow(TradeSwapFlowRequestModel model)
{
CheckNotNullSwapTradeFlow(model);
var swapFlow = new trade_swap_flow_more();
swapFlow.ClientNumber = model.ClientNumber;
swapFlow.ClientName = model.ClientName;
swapFlow.UnderlyingCode = model.UnderlyingCode;
swapFlow.UnderlyingName = model.UnderlyingName;
swapFlow.TraderName = model.TraderName;
swapFlow.AssetBookName = model.AssetBookName;
swapFlow.Notional = model.Notional;
swapFlow.BuySell = model.BuySell;
swapFlow.TradeNumber = model.TradeNumber;
swapFlow.TradeDate = model.TradeDate;
swapFlow.ExerciseDate = model.ExerciseDate;
swapFlow.Price = model.OpenPrice ?? 0;
swapFlow.CurrencyRate = model.CurrencyRate ?? 1;
swapFlow.AnnualRate = model.AnnualRate;
swapFlow.TotalFee = model.TotalFee;
swapFlow.MargeRate = model.MargeRate;
if (swapFlow.BuySell == "平仓")
{
swapFlow.UnwindDate = model.UnwindDate;
swapFlow.UnwindPrice = model.UnwindPrice;
swapFlow.UnwindNotional = model.UnwindNotional;
swapFlow.FixedIncome = model.FixedIncome;
swapFlow.Amount = model.Amount;
}
CheckAssignmentSwapTradeFlow(swapFlow);
swapFlow.OptId = UserId;
swapFlow.OptName = UserName;
swapFlow.OptDate = DateTime.Now;
DbContext.trade_swap_flow_more.Add(swapFlow);
DbContext.SaveChanges();
return swapFlow;
}
/// <summary>
/// 合成交易
/// </summary>
/// <param name="TradeNumber"></param>
/// <param name="tradeFlow"></param>
public void HandleSwapTrade(string TradeNumber)
{
using (var trans = BeginTransaction())
{
var tradeFlow = DbContext.trade_swap_flow_more.Where(x => !x.IsCompose && !x.IsDelete && x.TradeNumber == TradeNumber).ToList();
trade td = DbContext.trade.Where(x => x.TradeNumber == TradeNumber && x.ValidState != "InValid")?.FirstOrDefault();
if (td == null && !tradeFlow.Where(x => x.BuySell == "开仓").Any())
{
throw new ServiceException($"该交易不存在开仓流水,编号[{TradeNumber}]");
}
if (td != null && tradeFlow.Where(x => x.BuySell == "开仓").Any())
{
throw new ServiceException($"该交易重复,编号[{TradeNumber}]");
}
if (td != null)
{
tradeBLL.SetFieldsByTradeType(td);
}
if (tradeFlow.Where(x => x.BuySell == "开仓").Any())
{
var tradeflow = tradeFlow.Where(x => x.BuySell == "开仓").FirstOrDefault();
td = MapSwapTradeHandle(tradeflow);
InnerSaveSwapTrade(td, tradeflow);
}
if (tradeFlow.Where(x => x.BuySell == "平仓").Any())
{
var tradeflow = tradeFlow.Where(x => x.BuySell == "平仓").OrderBy(x => x.UnwindDate).ToList();
foreach (var item in tradeflow)
{
if (td.TradeStatus != "确认成交")
{
throw new ServiceException($"交易不允许平仓,编号[{TradeNumber}]");
}
UnwindSwapTrade(td, item);
}
}
tradeFlow.ForEach(x =>
{
x.IsCompose = true;
x.OptDate = DateTime.Now;
x.OptName = UserName;
x.OptId = UserId;
});
DbContext.SaveChanges();
trans.Commit();
}
}
private trade MapSwapTradeHandle(trade_swap_flow_more swapFlow)
{
var client = DataCacheProvider.GetClientDataSource().AsQueryable().FirstOrDefault(n => swapFlow.ClientNumber.Equals(n.Number, StringComparison.OrdinalIgnoreCase));
if (client == null)
{
throw new ServiceException($"该客户编号[{swapFlow.ClientNumber}]在系统中不存在");
}
trade td = new trade
{
ClientId = client.id,
ClientName = client.Name,
TradeNumber = swapFlow.TradeNumber,
UnderlyingCode = swapFlow.UnderlyingCode,
TradeDate = swapFlow.TradeDate,
StartDate = swapFlow.TradeDate,
ExerciseDate = swapFlow.ExerciseDate,
SettlementDate = swapFlow.ExerciseDate,
SpotPrice = swapFlow.Price,
Notional = Math.Abs(swapFlow.Notional),
AssetId = swapFlow.AssetId,
AssetBookName = swapFlow.AssetBookName,
TraderId = swapFlow.TraderId,
TraderName = swapFlow.TraderName,
TradeType = "收益互换",
StructureType = "收益互换",
OpponentRole = "甲方",
OptId = UserId,
OptName = UserName,
OptDate = DateTime.Now,
TradeSource = TradeSourceEnum..ToString(),
TradeStatus = ConsTrade.,
};
td.MetaDic["交易场所"] = "柜台市场";
if (!string.IsNullOrWhiteSpace(client.ClearingAgency))
{
td.MetaDic["清算机构"] = client.ClearingAgency;
}
td.MetaDic["主协议编号"] = client.MainProtocolCode;
td.MetaDic["补充协议编号"] = client.SupProtocolCode;
td.SettlementCurrency = client.SettlementCurrency ?? "CNY";
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
if (underlying == null)
{
throw new ServiceException($"该标的代码[{td.UnderlyingCode}]在系统中不存在");
}
else
{
td.UnderlyingId = underlying.id;
td.UnderlyingAssetClass = underlying.UnderlyingType;
td.MaturityDate = underlying.MaturityDate;
td.UnderlyingInstrumentType = underlying.UnderlyingInstrumentType;
td.UnderlyingAssetName = underlying.UnderlyingName;
}
var variety = DataCacheProvider.GetVarietyDataSource().GetData(underlying.UnderlyingTypeId);
td.QuoteCurrency = variety.QuoteCurrency ?? "CNY";
//交易份额--名义本金
td.Lots = td.Notional / underlying.ContractSize;
td.TradeAmount = td.Notional / variety.CountRatio;
td.OriginalNotional = td.Notional;
td.StockEqvNotional = (td.SpotPrice ?? 0) * td.Notional;
td.StockEqvNotionalReal = td.StockEqvNotional;
td.OriginalStockEqvNotional = td.StockEqvNotional;
//默认开仓不收取手续费
td.trade_swap.IsTradePriceWhenOpen = false; // 导入默认值
td.TradePrice = 0;
if (swapFlow.AnnualRate > 0)
{
td.trade_swap.GetSwapRate = swapFlow.AnnualRate ?? 0;
td.trade_swap.GetSwapTimeAndRate = td.ExerciseDate.Value.ToString("yyyy-MM-dd") + ";" + td.trade_swap.GetSwapRate;
td.trade_swap.IsGetFloatingProfit = false;
td.trade_swap.IsPayFloatingProfit = true;
td.trade_swap.PayLongShort = swapFlow.LongShort == "多头" ? "空头" : "多头";
td.trade_swap.PayUnderlyingId = td.UnderlyingId;
td.trade_swap.PayUnderlyingCode = td.UnderlyingCode;
td.trade_swap.PaySpotPrice = td.SpotPrice;
td.trade_swap.PayNotional = td.Notional;
td.trade_swap.PayLot = td.Lots;
td.trade_swap.PayTradeAmount = td.TradeAmount;
td.trade_swap.GetTradePrice = swapFlow.TotalFee;
td.trade_swap.GetSingleFee = swapFlow.TotalFee / td.Lots;
}
else
{
td.trade_swap.PaySwapRate = -swapFlow.AnnualRate ?? 0;
td.trade_swap.PaySwapTimeAndRate = td.ExerciseDate.Value.ToString("yyyy-MM-dd") + ";" + td.trade_swap.PaySwapRate;
td.trade_swap.IsGetFloatingProfit = true;
td.trade_swap.IsPayFloatingProfit = false;
td.trade_swap.GetLongShort = swapFlow.LongShort;
td.trade_swap.GetUnderlyingId = td.UnderlyingId;
td.trade_swap.GetUnderlyingCode = td.UnderlyingCode;
td.trade_swap.GetSpotPrice = td.SpotPrice;
td.trade_swap.GetNotional = td.Notional;
td.trade_swap.GetLot = td.Lots;
td.trade_swap.GetTradeAmount = td.TradeAmount;
td.trade_swap.PayTradePrice = -(swapFlow.TotalFee);
td.trade_swap.PaySingleFee = -(swapFlow.TotalFee / td.Lots);
}
if (swapFlow.MargeRate > 0)
{
td.trade_swap.GetMarginRate = swapFlow.MargeRate;
}
else
{
td.trade_swap.PayMarginRate = -swapFlow.MargeRate;
}
td.BuySell = td.TradePrice == 0 ? td.trade_swap.IsPayFloatingProfit == true ? "卖出" : "买入" : td.TradePrice > 0 ? "卖出" : "买入";
td.trade_swap.RateCalcMode = "01";
return td;
}
private void InnerSaveSwapTrade(trade importTrade, trade_swap_flow_more tradeflow)
{
importTrade.IsUsePremiumRate = true;
importTrade.IsTradePricePayType = true;
importTrade.PrincipalRate = 0;
importTrade.ParticipationRate = 1;
//预付金
importTrade.MarginTemplateName = "系统默认";
importTrade.MarginType = MarginTypeEnum.DEFAULT;
SetDBModelCreator(importTrade);
DbContext.trade.Add(importTrade);
DbContext.SaveChanges();
importTrade.trade_swap.TradeId = importTrade.id;
importTrade.trade_swap.SwapType = "普通";
importTrade.trade_swap.OptId = UserId;
importTrade.trade_swap.OptName = UserName;
importTrade.trade_swap.OptDate = DateTime.Now;
importTrade.trade_swap.SettlementPayType = 0;
importTrade.trade_swap.FlowId = tradeflow.id;
importTrade.trade_swap.AnnualDays = 365;
DbContext.trade_swap.Add(importTrade.trade_swap);
SaveTradeMeta(importTrade);
var tc = new trade_cash
{
ValidState = "Valid",
};
DbContext.trade_cash.Add(tc);
tc.OptId = UserId;
tc.OptName = UserName;
tc.OptDate = DateTime.Now;
tc.Action = ClientCashInCashOut._期权费;
//默认开仓不收取手续费 -- 期权费为0
tc.Amount = 0;
tc.QuoteAmount = 0;
tc.CurrencyRate = tradeflow.CurrencyRate;
tc.ExceciseType = "现金";
tc.TradeId = importTrade.id;
tc.ValueDate = importTrade.TradeDate.Value;
tc.Notional = importTrade.Notional;
tc.TradeAmount = importTrade.TradeAmount;
tc.Status = TradeCashStatusEnum.;
tc.TradeType = importTrade.BuySell;
DbContext.SaveChanges();
new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(importTrade, tc, tc.ValueDate);
var tcdGet = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = tc.Amount,
QuoteAmount = tc.QuoteAmount,
TradeCashType = TradeCashTypeEnum..ToString(),
ValueDate = tc.ValueDate,
IsForGet = true,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now
};
DbContext.trade_cash_detail.Add(tcdGet);
DbContext.SaveChanges();
}
private void UnwindSwapTrade(trade td, trade_swap_flow_more tradeflow)
{
UnwindSwapTradeCashHandle(td, tradeflow);
SaveTradeOperationHistory(td, "互换导入合成交易");
RemoveEodTradeAndFutureInfo(true, td.id, tradeflow.UnwindDate.Value);
}
private void UnwindSwapTradeCashHandle(trade td, trade_swap_flow_more tradeflow)
{
var unwindNotional = Math.Abs(tradeflow.UnwindNotional ?? 0);
var unwindType = td.Notional > unwindNotional ? "部分平仓" : "全部平仓";
var maxValueDate = DbContext.trade_cash.Where(x => x.TradeId == td.id && x.ValidState != "InValid" && x.Action != ClientCashInCashOut._期权费).OrderByDescending(x => x.ValueDate).Select(x => x.ValueDate)?.FirstOrDefault();
if (maxValueDate != null && maxValueDate > tradeflow.UnwindDate)
{
throw new ServiceException($"平仓日期({tradeflow.UnwindDate})不能小于历史平仓日期({maxValueDate})");
}
var client = DataCacheProvider.GetClientDataSource().GetData(td.ClientId);
var underly = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingId);
var variety = DataCacheProvider.GetVarietyDataSource().GetData(underly.UnderlyingTypeId);
var currencyRate = (tradeflow.CurrencyRate ?? 1);
//增加现金交割交易记录
var tc = new trade_cash();
DbContext.trade_cash.Add(tc);
tc.OptId = UserId;
tc.OptName = UserName;
tc.OptDate = DateTime.Now;
tc.TradeId = td.id;
tc.ExceciseType = "现金";
tc.TradeType = td.BuySell;
tc.CallPut = td.CallPut;
tc.Notional = td.Notional;
tc.TradeAmount = td.TradeAmount;
tc.IsLastAction = unwindType == "全部平仓";
tc.FinalPrice = td.SpotPrice;
tc.UnwindType = unwindType;
tc.UnwindPrice = Math.Abs(tradeflow.UnwindPrice ?? 0);
tc.CurrencyRate = currencyRate;
if (tc.UnwindType == "全部平仓")
{
tc.UnwindNotional = td.Notional;
tc.UnwindTradeAmount = td.TradeAmount;
tc.UnwindPercentRate = td.Notional / td.OriginalNotional;
}
else
{
tc.UnwindNotional = unwindNotional;
tc.UnwindTradeAmount = unwindNotional / variety.CountRatio;
tc.UnwindPercentRate = unwindNotional / td.OriginalNotional;
}
// 开仓默认不收取手续费
var costTradePriceGetQuote = PayoffSwapCalcService.GetCostFee(td, td, tc, td.trade_swap.IsPayFloatingProfit ? true : false, true);
var costTradePriceGet = costTradePriceGetQuote * currencyRate;
var costFeeGetQuote = (tradeflow.TotalFee ?? 0);
var costFeeGet = costFeeGetQuote * currencyRate;
var amountQuote = (tradeflow.Amount ?? 0);
var amount = amountQuote * currencyRate;
var FixedIncomeQuote = (tradeflow.FixedIncome ?? 0);
var FixedIncome = FixedIncomeQuote * currencyRate;
var initialAmountPayQuote = amountQuote - costFeeGetQuote - costTradePriceGetQuote - FixedIncomeQuote;
var initialAmountPay = initialAmountPayQuote * currencyRate;
tc.NotionalPercentRate = tc.UnwindPercentRate;
tc.Action = ClientCashInCashOut._平仓费;
tc.Status = TradeCashStatusEnum.;
tc.Amount = amount;
tc.QuoteAmount = amountQuote;
tc.ValueDate = tradeflow.UnwindDate ?? DateTime.Today;
tc.ValidState = "Valid";
tc.ExerciseWay = tc.ValueDate == td.ExerciseDate ? TradeCashExerciseWayEnum. : TradeCashExerciseWayEnum.;
DbContext.SaveChanges();
if (unwindType == "全部平仓")
{
td.TradeStatus = "已平仓";
}
else
{
td.HasPartialUnWind = 1;
}
td.UnWindDate = tc.ValueDate;
td.StockEqvNotional -= (td.SpotPrice ?? 0) * (tc.UnwindNotional ?? 0);
td.Notional -= tc.UnwindNotional ?? 0;
td.Lots = td.Notional / underly.ContractSize;
td.TradeAmount -= tc.UnwindTradeAmount ?? 0;
td.UnWindNotional = (td.UnWindNotional ?? 0) + tc.UnwindNotional;
//增加出入金记录
new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, tc, tc.ValueDate);
var trade_cash_swap = new trade_cash_swap();
trade_cash_swap.StartDate = td.StartDate.Value;
var costFeesum = costFeeGet + costTradePriceGet;
if (FixedIncomeQuote > 0)
{
trade_cash_swap.GetExtraAmount = FixedIncomeQuote;
}
else
{
trade_cash_swap.PayExtraAmount = -FixedIncomeQuote;
}
if (td.trade_swap.IsPayFloatingProfit)
{
trade_cash_swap.PayInitialAmount = -initialAmountPay;
trade_cash_swap.PayStartPrice = td.trade_swap.PayFinalPrice ?? td.trade_swap.PaySpotPrice;
trade_cash_swap.PayFinalPrice = tc.FinalPrice;
trade_cash_swap.GetCostFee = costFeesum;
}
else
{
trade_cash_swap.GetInitialAmount = initialAmountPay;
trade_cash_swap.GetStartPrice = td.trade_swap.PayFinalPrice ?? td.trade_swap.GetSpotPrice;
trade_cash_swap.GetFinalPrice = tc.FinalPrice;
trade_cash_swap.PayCostFee = -costFeesum;
}
trade_cash_swap.GetAmount = trade_cash_swap.GetInitialAmount + (trade_cash_swap.GetExtraAmount ?? 0) * currencyRate + (trade_cash_swap.GetCostFee ?? 0);
trade_cash_swap.PayAmount = trade_cash_swap.PayInitialAmount + (trade_cash_swap.PayExtraAmount ?? 0) * currencyRate + (trade_cash_swap.PayCostFee ?? 0);
trade_cash_swap.TradeId = tc.TradeId;
trade_cash_swap.TradeCashId = tc.id;
trade_cash_swap.OptId = tc.OptId;
trade_cash_swap.OptName = tc.OptName;
trade_cash_swap.OptDate = DateTime.Now;
trade_cash_swap.FlowId = tradeflow.id;
DbContext.trade_cash_swap.Add(trade_cash_swap);
var tcdFixed = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = FixedIncome,
QuoteAmount = FixedIncomeQuote,
ValueDate = tc.ValueDate,
IsForGet = false,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum..ToString()
};
DbContext.trade_cash_detail.Add(tcdFixed);
var tcdCostTradePriceGet = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = costTradePriceGet,
QuoteAmount = costTradePriceGetQuote,
ValueDate = tc.ValueDate,
IsForGet = true,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum..ToString()
};
DbContext.trade_cash_detail.Add(tcdCostTradePriceGet);
var tcdCostFeeGet = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = costFeeGet,
QuoteAmount = costFeeGetQuote,
ValueDate = tc.ValueDate,
IsForGet = true,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum..ToString()
};
DbContext.trade_cash_detail.Add(tcdCostFeeGet);
var tcdPay = new trade_cash_detail
{
TradeId = tc.TradeId,
TradeCashId = tc.id,
Action = tc.Action,
Amount = initialAmountPay,
QuoteAmount = initialAmountPayQuote,
ValueDate = tc.ValueDate,
IsForGet = false,
OptId = tc.OptId,
OptName = tc.OptName,
OptDate = DateTime.Now,
TradeCashType = TradeCashTypeEnum..ToString()
};
DbContext.trade_cash_detail.Add(tcdPay);
DbContext.SaveChanges();
}
private void SaveTradeMeta(trade t)
{
if (t != null && t.MetaDic != null && t.MetaDic.Count() > 0)
{
foreach (var kv in t.MetaDic)
{
if (!string.IsNullOrEmpty(kv.Value))
{
AddTradeMeta(false, t.id, kv.Key, kv.Value);
}
}
}
}
public void UpdateCurrencyRate(IEnumerable<int> ids, double CurrencyRate)
{
if (ids is null || !ids.Any(n => n > 0))
{
throw new ArgumentException("tradeids 参数无效", nameof(ids));
}
using (var trans = BeginTransaction())
{
var idSet = ids.ToHashSet();
var tradeFlow = DbContext.trade_swap_flow_more.Where(x => idSet.Contains(x.id)).ToList();
tradeFlow.ForEach(x =>
{
x.CurrencyRate = CurrencyRate;
x.OptDate = DateTime.Now;
x.OptName = UserName;
x.OptId = UserId;
});
//开仓 -- 开仓默认不收手续费
var tradeid_Open = DbContext.trade_swap.Where(x => idSet.Contains(x.FlowId ?? 0)).Select(x => x.TradeId).ToHashSet();
if (tradeid_Open.Any())
{
var trade_cash_Open = DbContext.trade_cash.Where(x => tradeid_Open.Contains(x.TradeId) && x.ValidState != "InValid" && x.Action == ClientCashInCashOut._期权费).ToList();
trade_cash_Open.ForEach(x =>
{
x.CurrencyRate = CurrencyRate;
x.OptDate = DateTime.Now;
x.OptName = UserName;
x.OptId = UserId;
});
}
//平仓
var trade_cash_swap = DbContext.trade_cash_swap.Where(x => idSet.Contains(x.FlowId ?? 0)).ToList();
if (trade_cash_swap.Any())
{
List<TradeAuditLog> tradeAudits = new List<TradeAuditLog>();
trade_cash_swap.ForEach(x =>
{
x.GetAmount = x.GetInitialAmount + (x.GetExtraAmount ?? 0) * CurrencyRate + (x.GetCostFee ?? 0);
x.PayAmount = x.PayInitialAmount + (x.PayExtraAmount ?? 0) * CurrencyRate + (x.PayCostFee ?? 0);
});
var trade_cash_id_Un = trade_cash_swap.Select(x => x.TradeCashId).ToHashSet();
var trade_cash_Un = DbContext.trade_cash.Where(x => trade_cash_id_Un.Contains(x.id) && x.ValidState != "InValid" && x.Action != ClientCashInCashOut._期权费).ToList();
foreach (var item in trade_cash_Un)
{
var changsStr = "trade_cash.id:" + item.id + "; 汇率:" + (item.CurrencyRate ?? 0).ToString("0.0000") + "改为" + CurrencyRate.ToString("0.0000");
TradeAuditLog log = new TradeAuditLog()
{
TradeId = item.TradeId,
AuditFlag = TradeAuditFlag.operation,
OptType = "修改平仓汇率",
Changes = changsStr,
DataType = "00",
OptId = UserId,
OptName = UserName,
OptDate = OptDate
};
tradeAudits.Add(log);
item.CurrencyRate = CurrencyRate;
item.Amount = (item.QuoteAmount ?? 0) * CurrencyRate;
item.OptDate = DateTime.Now;
item.OptName = UserName;
item.OptId = UserId;
}
var ClientCashInCashOuts = DbContext.ClientCashInCashOut.Where(x => trade_cash_id_Un.Contains(x.TradeCashId)).ToList();
ClientCashInCashOuts.ForEach(x =>
{
var Amount = trade_cash_Un.FirstOrDefault(y => y.id == x.TradeCashId).Amount;
x.Money = -Amount;
});
var trade_cash_detail = DbContext.trade_cash_detail.Where(x => trade_cash_id_Un.Contains(x.TradeCashId)).ToList();
trade_cash_detail.ForEach(x =>
{
x.Amount = (x.QuoteAmount ?? 0) * CurrencyRate;
x.OptDate = DateTime.Now;
x.OptName = UserName;
x.OptId = UserId;
});
DbContext.TradeAuditLog.AddRange(tradeAudits);
}
DbContext.SaveChanges();
trans.Commit();
}
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,191 @@
using System.Data;
using System.Linq.Expressions;
using YLErp.Models;
using YLErp.Modules.EodModule;
using YLErp.Office.ExcelModule;
namespace YLErp.Modules.TradeModule.SwapModule
{
/// <summary>
/// 场外期权交易列表导出服务
/// </summary>
public class SwapTradeListExportService : TradeQueryService
{
public SwapTradeListExportService(OptUserInfo userInfo) : base(userInfo)
{
}
public SwapTradeListExportService(YLBaseService baseService) : base(baseService)
{
}
/// <summary>
/// 导出所有字段
/// </summary>
public byte[] ExportAllFieldsToExcel(TradeMultiCloseQueryModel queryModel, List<int> userAsset, bool isShowAll = false)
{
if (queryModel is null)
{
throw new ArgumentNullException(nameof(queryModel));
}
var list = CreateQuery(queryModel, userAsset, isShowAll);
var tradeCashIds = list.Select(x => x.TcId).ToList();
var tradeCashDetails = DbContext.trade_cash_detail.Where(x => tradeCashIds.Contains(x.TradeCashId));
var clientVarietyConfigs = DbContext.client_variety_config.ToList();
var currencyRateService = new EodCurrencyRateService(OptUserInfo.SystemUser);
foreach (var item in list)
{
if (item.CommissionSingleFee == null && item.CommissionRate == null)
{
var clientVarietyConfig = clientVarietyConfigs.Where(x => x.ClientId == item.ClientId && x.VarietyId == item.VarietyId && x.ValueDate <= item.TcHappenDate).OrderByDescending(x => x.ValueDate).FirstOrDefault();
if (clientVarietyConfig != null)
{
item.CommissionRate = clientVarietyConfig.UnAnnualRate;
item.CommissionSingleFee = clientVarietyConfig.SingleFee;
}
}
var client = DataCacheProvider.GetClientDataSource().GetData(item.ClientId);
item.BoundSide = client.BoundSide.ToString();
item.DayCount = (item.TcHappenDate - item.TradeDate).Value.Days;
item.OpenCurrencyRate = currencyRateService.GetCurrencyRate(item.QuoteCurrency, item.SettlementCurrency, item.TradeDate.Value);
item.TcStockEqvNotional = item.TcNotional * item.SpotPrice * item.OpenCurrencyRate;
item.TcRemainStockEqvNotional = (item.TcPreNotional - item.TcNotional) * item.SpotPrice * item.OpenCurrencyRate;
item.OpenCommision = -tradeCashDetails.FirstOrDefault(x => x.TradeCashId == item.TcId && x.TradeCashType == "开仓手续费")?.Amount;
item.TcCommission = -tradeCashDetails.FirstOrDefault(x => x.TradeCashId == item.TcId && x.TradeCashType == "了结手续费")?.Amount;
item.AnnualFee = -tradeCashDetails.FirstOrDefault(x => x.TradeCashId == item.TcId && x.TradeCashType == "利息")?.Amount;
item.FloatingWinLoss = -tradeCashDetails.FirstOrDefault(x => x.TradeCashId == item.TcId && x.TradeCashType == "浮动收益")?.Amount;
}
var templateFile = OtcAppContext.MapPath("~/App_Docs/导出模板/互换交易平仓记录导出模板.xlsx");
return ExcelGenerator.UseTemplateGenerator(templateFile).AddVariable(new { list = list }).GenerateBytes();
}
private IList<SwapTradeUnwindDetail> CreateQuery(TradeMultiCloseQueryModel queryModel, List<int> userAsset, bool isShowAll)
{
if (queryModel is null)
{
throw new ArgumentNullException(nameof(queryModel));
}
BuildPredicate(queryModel, out var tdPredicate, out var tcPredicate);
var query = from t in DbContext.trade.Where(tdPredicate)
join ts in DbContext.trade_swap on t.id equals ts.TradeId
join tc in DbContext.trade_cash.Where(tcPredicate) on t.id equals tc.TradeId
join tcs in DbContext.trade_cash_swap on tc.id equals tcs.TradeCashId
join flow in DbContext.trade_swap_flow on tcs.FlowId equals flow.id
join un in DbContext.underlying_manager on t.UnderlyingId equals un.id
select new SwapTradeUnwindDetail
{
Id = t.id,
TcId = tc.id,
ClientId = t.ClientId,
VarietyId = un.UnderlyingTypeId,
TradeNumber = t.TradeNumber,
TradeFlowNumber = flow.Number,
ClientName = t.ClientName,
AssetBookName = t.AssetBookName,
TradeDate = t.TradeDate,
BuySell = ts.PayLongShort == "多头" ? "客户买入" : "客户卖出",
TradeType = t.TradeType,
UnderlyingCode = t.UnderlyingCode,
SpotPrice = t.SpotPrice,
QuoteCurrency = t.QuoteCurrency,
SettlementCurrency = t.SettlementCurrency,
TcUnwindType = (tc.UnwindType == "到期行权" || tc.ValueDate == flow.SettlementDate) ? "到期" : "提前",
TcCurrencyRate = tc.CurrencyRate,
TcUnwindTradeAmount = tc.UnwindTradeAmount,
TcPreNotional = tc.Notional,
TcNotional = tc.UnwindNotional,
TcAmount = -tc.Amount,
PaySide = tc.Amount > 0 ? "乙方" : "甲方",
Size = un.ContractSize,
TcValueDate = tc.ValueDate,
TcHappenDate = tc.HappenedDate ?? tc.ValueDate,
TcFinalPrice = tc.FinalPrice,
CommissionSingleFee = flow.SingleFee,
CommissionRate = flow.UnAnnualRate,
};
return query.OrderByDescending(x => x.TcId).ToList();
}
//构建查询条件
private void BuildPredicate(TradeMultiCloseQueryModel queryModel, out Expression<Func<trade, bool>> tdPredicate
, out Expression<Func<trade_cash, bool>> tcPredicate)
{
tdPredicate = PredicateBuilder.Create<trade>(t => t.ClientId > 0 && t.IsGroup != 2);
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 (!string.IsNullOrWhiteSpace(queryModel.TradeNumber))
{
var TradeNumber = queryModel.TradeNumber.Trim();
tdPredicate = tdPredicate.And(n => n.TradeNumber.Contains(TradeNumber));
}
if (!string.IsNullOrWhiteSpace(queryModel.BuySell))
{
var BuySell = queryModel.BuySell.Trim();
tdPredicate = tdPredicate.And(n => n.BuySell == BuySell);
}
if (queryModel.ClientIdList != null && queryModel.ClientIdList.Any(n => n > 0))
{
tdPredicate = tdPredicate.And(n => queryModel.ClientIdList.Contains(n.ClientId));
}
if (queryModel.UnderlyingIdList != null && queryModel.UnderlyingIdList.Any(n => n > 0))
{
tdPredicate = tdPredicate.And(n => queryModel.UnderlyingIdList.Contains(n.UnderlyingId));
}
//--------------------------------------------------------
tcPredicate = PredicateBuilder.Create<trade_cash>(tc => tc.ValidState != ConsGlobal.InValid && !tc.IsDeleted
&& (tc.Action == "系统操作-行权费" || tc.Action == "系统操作-平仓费" || tc.Action == "系统操作-票息" || tc.Action == "系统操作-互换"));
if (queryModel.TradeCashIdList != null && queryModel.TradeCashIdList.Any(x => x > 0))
{
tcPredicate = tcPredicate.And(tc => queryModel.TradeCashIdList.Contains(tc.id));
}
if (queryModel.UnwindDateStart != null)
{
var UnwindDateStart = queryModel.UnwindDateStart.Value;
tcPredicate = tcPredicate.And(tc => tc.HappenedDate.Value >= UnwindDateStart || tc.ValueDate >= UnwindDateStart);
}
if (queryModel.UnwindDateEnd != null)
{
var UnwindDateEnd = queryModel.UnwindDateEnd.Value;
tcPredicate = tcPredicate.And(tc => tc.ValueDate <= UnwindDateEnd);
}
}
}
}
File diff suppressed because it is too large Load Diff