3231 lines
146 KiB
C#
3231 lines
146 KiB
C#
using System.Data;
|
|
using System.Globalization;
|
|
using System.Text.RegularExpressions;
|
|
using YLErp.BLL;
|
|
using YLErp.Commons;
|
|
using YLErp.Configuration;
|
|
using YLErp.CustomizedBizLogic;
|
|
using YLErp.DBModels.Consts;
|
|
using YLErp.DBModels.Enums;
|
|
using YLErp.Enums;
|
|
using YLErp.Model.Enum;
|
|
using YLErp.Modules.CalculationModule;
|
|
using YLErp.Modules.EodModule;
|
|
using YLErp.Modules.TradeModule.OrderModule;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.Modules.TradeModule.SwapModule
|
|
{
|
|
public class SwapTradeImportService : TradeServiceBase
|
|
{
|
|
public SwapTradeImportService(YLBaseService baseService) : base(baseService)
|
|
{
|
|
}
|
|
|
|
public SwapTradeImportService(OptUserInfo userInfo) : base(userInfo)
|
|
{
|
|
}
|
|
|
|
/// <summary>
|
|
/// 从excel文件中导入场外期权交易
|
|
/// </summary>
|
|
public void ImportSwapTradesFromExcel(Stream streamIn, out int totalNum, out int successNum)
|
|
{
|
|
if (PS.Config.Company == CompanyEnum.山西)
|
|
{
|
|
ImportFromExcelSX(streamIn, out totalNum, out successNum);
|
|
}
|
|
else
|
|
{
|
|
ImportFromExcel(streamIn, out totalNum, out successNum);
|
|
}
|
|
}
|
|
|
|
#region 普通互换交易导入
|
|
|
|
/// <summary>
|
|
/// 导入交易
|
|
/// </summary>
|
|
/// <param name="streamIn"></param>
|
|
/// <param name="totalNum">当前文件中的目标期权总条数</param>
|
|
/// <param name="successNum">成功入库的数量</param>
|
|
public void ImportFromExcel(Stream streamIn, out int totalNum, out int successNum)
|
|
{
|
|
totalNum = 0;
|
|
successNum = 0;
|
|
|
|
var rowIndex = 0;
|
|
var groupTradeList = new List<OtcOptionTradeFullEx>();
|
|
var structureTradeList = new List<OtcOptionTradeFullEx>();
|
|
|
|
try
|
|
{
|
|
var ds = Office.ExcelHelper.ReadExcelAsDataSet(streamIn, new[] { 0 }, 0);
|
|
|
|
if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 3)
|
|
{
|
|
throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" };
|
|
}
|
|
|
|
var table = ds.Tables[0];
|
|
var reader = new DataRowTopTypeReader(table);
|
|
|
|
rowIndex = 2;
|
|
totalNum = table.Rows.Count - rowIndex;
|
|
|
|
foreach (var row in table.Rows.Cast<DataRow>().Skip(2))
|
|
{
|
|
using (var trans = BeginTransaction())
|
|
{
|
|
rowIndex++;
|
|
|
|
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
|
|
{
|
|
totalNum--;
|
|
continue;
|
|
}
|
|
|
|
reader.SetDataRow(row);
|
|
|
|
//映射导入数据到交易对象
|
|
HandleTrade(reader);
|
|
|
|
successNum++;
|
|
|
|
trans.Commit();
|
|
}
|
|
}
|
|
}
|
|
catch (ServiceException se)
|
|
{
|
|
if (se.Tag != null)
|
|
{
|
|
throw;
|
|
}
|
|
|
|
throw new ServiceException($"已成功导入{successNum}条;\n第{rowIndex}行,{se.Message}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogFactory.GetLogger("导入期权交易").Error(ex);
|
|
throw new ServiceException($"已成功导入{successNum}条,\n第{rowIndex}行,发生错误:{ex.Message}", ex);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 导入交易
|
|
/// </summary>
|
|
/// <param name="streamIn"></param>
|
|
/// <param name="totalNum">当前文件中的目标期权总条数</param>
|
|
/// <param name="successNum">成功入库的数量</param>
|
|
public void ImportToEndSwapTradesFromExcel(Stream streamIn, out int totalNum, out int successNum)
|
|
{
|
|
totalNum = 0;
|
|
successNum = 0;
|
|
|
|
var rowIndex = 0;
|
|
try
|
|
{
|
|
var ds = Office.ExcelHelper.ReadExcelAsDataSet(streamIn, new[] { 0 }, 0);
|
|
|
|
if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 2)
|
|
{
|
|
throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" };
|
|
}
|
|
|
|
var table = ds.Tables[0];
|
|
var reader = new DataRowReader(table, 0);
|
|
|
|
rowIndex = 1;
|
|
totalNum = table.Rows.Count - rowIndex;
|
|
|
|
foreach (var row in table.Rows.Cast<DataRow>().Skip(1))
|
|
{
|
|
using (var trans = BeginTransaction())
|
|
{
|
|
rowIndex++;
|
|
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
|
|
{
|
|
totalNum--;
|
|
continue;
|
|
}
|
|
reader.SetDataRow(row);
|
|
|
|
HandleToEndSwapTrade(reader);
|
|
|
|
successNum++;
|
|
|
|
trans.Commit();
|
|
}
|
|
}
|
|
}
|
|
catch (ServiceException se)
|
|
{
|
|
if (se.Tag != null)
|
|
{
|
|
throw;
|
|
}
|
|
|
|
throw new ServiceException($"已成功导入{successNum}条;\n第{rowIndex}行,{se.Message}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogFactory.GetLogger("导入收益互换了结").Error(ex);
|
|
throw new ServiceException($"已成功导入{successNum}条,\n第{rowIndex}行,发生错误:{ex.Message}", ex);
|
|
}
|
|
}
|
|
|
|
|
|
private trade HandleTrade(DataRowTopTypeReader reader)
|
|
{
|
|
var td = new trade();
|
|
td.trade_swap = new trade_swap();
|
|
//基本要素
|
|
td.TradeNumber = reader.GetString("交易编号", false);
|
|
|
|
td.AssetBookName = reader.GetString("簿记账户名称", true);
|
|
td.TraderName = reader.GetString("交易员名称", true);
|
|
new OtcOptionSaveChecker(this).CheckAssetBook(td).CheckTrader(td);
|
|
|
|
td.TradeType = "收益互换";
|
|
td.ClientName = reader.GetString("交易对手方名称", true);
|
|
|
|
if (string.IsNullOrWhiteSpace(td.ClientName))
|
|
{
|
|
throw new ServiceException("交易对手方名称 必须填写");
|
|
}
|
|
|
|
//交易日期
|
|
td.TradeDate = reader.GetDate("成交日期", true);
|
|
td.StartDate = reader.GetDate("开始日期", true);
|
|
td.ExerciseDate = reader.GetDate("到期日期", true);
|
|
td.SettlementDate = td.ExerciseDate;
|
|
|
|
td.StockEqvNotional = reader.GetDouble("名义本金", true) ?? 0;
|
|
td.trade_swap.AnnualDays = reader.GetInt("年化天数", true);
|
|
td.trade_swap.AnnualVarIncome = reader.GetString("浮动收益年化", true) == "是";
|
|
td.trade_swap.RateCalcMode = GetRateCalcMode(reader.GetString("计息方式", true));
|
|
td.trade_swap.IsTradePriceWhenOpen = reader.GetString("是否开仓时收取开仓费", true) == "是";
|
|
td.trade_swap.IsShare = reader.GetString("收费基本单位", true) == "手数";
|
|
var ExchangeRate = reader.GetDouble("汇率", false);
|
|
td.Comments = reader.GetString("备注", false);
|
|
var clientQuery = DbContextFactory.GetClientDbContext(OptUser).client.AsQueryable();
|
|
if (!string.IsNullOrWhiteSpace(td.ClientName))
|
|
{
|
|
clientQuery = clientQuery.Where(c => c.Name == td.ClientName);
|
|
}
|
|
var client = clientQuery.Select(n => new { n.id, n.SettlementCurrency, n.DerivativesInvestmentVarieties,n.IsCentralClearing,n.CentralClearingPaltform,n.TradingPaltform }).FirstOrDefault();
|
|
|
|
if (client == null)
|
|
{
|
|
throw new ServiceException($"交易对手方不存在,客户名称:{td.ClientName}");
|
|
}
|
|
else
|
|
{
|
|
if (!string.IsNullOrEmpty(client.IsCentralClearing))
|
|
{
|
|
td.MetaDic.Add("中央对手方清算", client.IsCentralClearing);
|
|
}
|
|
if (!string.IsNullOrEmpty(client.IsCentralClearing))
|
|
{
|
|
td.MetaDic.Add("中央清算平台", client.CentralClearingPaltform);
|
|
}
|
|
if (!string.IsNullOrEmpty(client.IsCentralClearing))
|
|
{
|
|
td.MetaDic.Add("交易平台", client.TradingPaltform);
|
|
}
|
|
|
|
if (!client.DerivativesInvestmentVarieties.Contains((int)DerivativesInvestmentVarietiesEnum.场外互换 + ""))
|
|
{
|
|
throw new ServiceException($"客户:{td.ClientName}未设置交易种类“场外互换”,无法生成互换交易!");
|
|
}
|
|
}
|
|
|
|
td.ClientId = client.id;
|
|
td.SettlementCurrency = client.SettlementCurrency;
|
|
|
|
td.OpponentRole = "甲方";
|
|
|
|
var um = new underlying_manager();
|
|
var singleFee = 0.0;
|
|
|
|
#region 交易员收取信息读取
|
|
|
|
reader.SetTopType("交易员收取");
|
|
td.trade_swap.GetLongShort = reader.GetString("多头空头", false);
|
|
if (!string.IsNullOrWhiteSpace(td.trade_swap.GetLongShort))
|
|
{
|
|
td.trade_swap.IsGetFloatingProfit = true;
|
|
td.trade_swap.GetUnderlyingCode = reader.GetString("标的代码", true);
|
|
|
|
um = DataCacheProvider.GetUnderlyingDataSource().GetData(td.trade_swap.GetUnderlyingCode);
|
|
if (um == null)
|
|
{
|
|
throw new ServiceException($"{td.trade_swap.GetUnderlyingCode} 不存在,请先新建标的再导入");
|
|
}
|
|
|
|
td.trade_swap.GetUnderlyingId = um.id;
|
|
td.UnderlyingId = um.id;
|
|
td.UnderlyingCode = um.UnderlyingCode;
|
|
td.UnderlyingName = um.UnderlyingName;
|
|
td.UnderlyingInstrumentType = um.UnderlyingInstrumentType;
|
|
|
|
if (!td.trade_swap.IsShare)
|
|
{
|
|
td.trade_swap.GetNotional = reader.GetDouble("份额/手数", true);
|
|
td.trade_swap.GetTradeAmount = td.trade_swap.GetNotional / um.CountRatio;
|
|
td.trade_swap.GetLot = td.trade_swap.GetNotional / um.ContractSize;
|
|
}
|
|
else
|
|
{
|
|
td.trade_swap.GetLot = reader.GetDouble("份额/手数", true);
|
|
td.trade_swap.GetNotional = td.trade_swap.GetLot * um.ContractSize;
|
|
td.trade_swap.GetTradeAmount = td.trade_swap.GetNotional / um.CountRatio;
|
|
}
|
|
|
|
td.Notional = td.trade_swap.GetNotional ?? 0;
|
|
td.TradeAmount = td.trade_swap.GetTradeAmount ?? 0;
|
|
td.Lots = td.trade_swap.GetLot;
|
|
|
|
//判断是否组合标的
|
|
var synthetic = DataCacheProvider.GetUnderlyingDataSource().GetSyntheticUnderlying(um.UnderlyingCode);
|
|
//读取组合标的
|
|
if (synthetic != null)
|
|
{
|
|
reader.SetTopType("组合标的");
|
|
var sulist = new List<UnderlyingPriceModel>(4);
|
|
var model = synthetic.GetSyntheticPriceModel();
|
|
var codeSet = model.SuList.Select(n => n.UnderlyingCode).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
for (var i = 1; i <= 4; i++)
|
|
{
|
|
var code = reader.GetString("标的" + i + "_代码");
|
|
if (string.IsNullOrWhiteSpace(code))
|
|
{
|
|
continue;
|
|
}
|
|
if (!codeSet.Remove(code))
|
|
{
|
|
throw new ServiceException($"[组合标的]标的{i}_代码 填写错误,组合标的中不存在此标的:{code}");
|
|
}
|
|
model.SuList.First(n => n.UnderlyingCode.Equals(code, StringComparison.OrdinalIgnoreCase)).Price = reader.GetDouble("标的" + i + "_价格", true).Value;
|
|
}
|
|
if (codeSet.Any())
|
|
{
|
|
throw new ServiceException("[组合标的]未填写完整");
|
|
}
|
|
td.trade_swap.GetSpotPrice = model.Price = model.SuList.Sum(n => n.Coefficient * n.Price) + model.Constant;
|
|
td.MetaDic["组合标的"] = JsonHelper.ToJson(model);
|
|
}
|
|
else
|
|
{
|
|
td.trade_swap.GetSpotPrice = reader.GetDouble("期初标的价格", true);
|
|
}
|
|
td.SpotPrice = td.trade_swap.GetSpotPrice;
|
|
}
|
|
else
|
|
{
|
|
var str = reader.GetString("单位交易费用", true);
|
|
|
|
if (!string.IsNullOrWhiteSpace(str))
|
|
{
|
|
var percent = str.EndsWith("%");
|
|
|
|
if (percent)
|
|
{
|
|
var strTrim = str.TrimEnd('%');
|
|
if (double.TryParse(strTrim, out var num))
|
|
{
|
|
td.trade_swap.GetUnAnnualRate = num / 100;
|
|
}
|
|
else
|
|
{
|
|
throw new ServiceException($"[交易员收取]单位交易费用 填写错误:{str}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (double.TryParse(str, out var num))
|
|
{
|
|
singleFee = num;
|
|
}
|
|
else
|
|
{
|
|
throw new ServiceException($"[交易员收取]单位交易费用 填写错误:{str}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
td.trade_swap.GetSwapRate = reader.GetPercent("互换利率(年化)", false) ?? 0;
|
|
if (td.trade_swap.GetSwapRate != 0)
|
|
{
|
|
td.trade_swap.GetSwapTimeAndRate = td.ExerciseDate.Value.ToString("yyyy-MM-dd") + ";" + td.trade_swap.GetSwapRate;
|
|
}
|
|
td.trade_swap.GetMarginRate = reader.GetPercent("初始预付金率", false) ?? 0;
|
|
|
|
#endregion
|
|
|
|
#region 交易员支付信息读取
|
|
|
|
reader.SetTopType("交易员支付");
|
|
td.trade_swap.PayLongShort = reader.GetString("多头空头", false);
|
|
if (!string.IsNullOrWhiteSpace(td.trade_swap.PayLongShort))
|
|
{
|
|
td.trade_swap.IsPayFloatingProfit = true;
|
|
td.trade_swap.PayUnderlyingCode = reader.GetString("标的代码", true);
|
|
|
|
um = DataCacheProvider.GetUnderlyingDataSource().GetData(td.trade_swap.PayUnderlyingCode);
|
|
if (um == null)
|
|
{
|
|
throw new ServiceException($"{td.trade_swap.PayUnderlyingCode} 不存在,请先新建标的再导入");
|
|
}
|
|
|
|
td.trade_swap.PayUnderlyingId = um.id;
|
|
td.UnderlyingId = um.id;
|
|
td.UnderlyingCode = um.UnderlyingCode;
|
|
td.UnderlyingName = um.UnderlyingName;
|
|
td.UnderlyingInstrumentType = um.UnderlyingInstrumentType;
|
|
|
|
if (!td.trade_swap.IsShare)
|
|
{
|
|
td.trade_swap.PayNotional = reader.GetDouble("份额/手数", true);
|
|
td.trade_swap.PayTradeAmount = td.trade_swap.PayNotional / um.CountRatio;
|
|
td.trade_swap.PayLot = td.trade_swap.PayNotional / um.ContractSize;
|
|
}
|
|
else
|
|
{
|
|
td.trade_swap.PayLot = reader.GetDouble("份额/手数", true);
|
|
td.trade_swap.PayNotional = td.trade_swap.PayLot * um.ContractSize;
|
|
td.trade_swap.PayTradeAmount = td.trade_swap.PayNotional / um.CountRatio;
|
|
}
|
|
|
|
td.Notional = td.trade_swap.PayNotional ?? 0;
|
|
td.TradeAmount = td.trade_swap.PayTradeAmount ?? 0;
|
|
td.Lots = td.trade_swap.PayLot;
|
|
|
|
|
|
//判断是否组合标的
|
|
var synthetic = DataCacheProvider.GetUnderlyingDataSource().GetSyntheticUnderlying(um.UnderlyingCode);
|
|
//读取组合标的
|
|
if (synthetic != null)
|
|
{
|
|
reader.SetTopType("组合标的");
|
|
var sulist = new List<UnderlyingPriceModel>(4);
|
|
var model = synthetic.GetSyntheticPriceModel();
|
|
var codeSet = model.SuList.Select(n => n.UnderlyingCode).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
for (var i = 1; i <= 4; i++)
|
|
{
|
|
var code = reader.GetString("标的" + i + "_代码");
|
|
if (string.IsNullOrWhiteSpace(code))
|
|
{
|
|
continue;
|
|
}
|
|
if (!codeSet.Remove(code))
|
|
{
|
|
throw new ServiceException($"[组合标的]标的{i}_代码 填写错误,组合标的中不存在此标的:{code}");
|
|
}
|
|
model.SuList.First(n => n.UnderlyingCode.Equals(code, StringComparison.OrdinalIgnoreCase)).Price = reader.GetDouble("标的" + i + "_价格", true).Value;
|
|
}
|
|
if (codeSet.Any())
|
|
{
|
|
throw new ServiceException("[组合标的]未填写完整");
|
|
}
|
|
td.trade_swap.PaySpotPrice = model.Price = model.SuList.Sum(n => n.Coefficient * n.Price) + model.Constant;
|
|
td.MetaDic["组合标的2"] = JsonHelper.ToJson(model);
|
|
}
|
|
else
|
|
{
|
|
td.trade_swap.PaySpotPrice = reader.GetDouble("期初标的价格", true);
|
|
}
|
|
td.SpotPrice = td.trade_swap.PaySpotPrice;
|
|
}
|
|
else
|
|
{
|
|
var str = reader.GetString("单位交易费用", true);
|
|
|
|
if (!string.IsNullOrWhiteSpace(str))
|
|
{
|
|
var percent = str.EndsWith("%");
|
|
|
|
if (percent)
|
|
{
|
|
var strTrim = str.TrimEnd('%');
|
|
if (double.TryParse(strTrim, out var num))
|
|
{
|
|
td.trade_swap.PayUnAnnualRate = num / 100;
|
|
}
|
|
else
|
|
{
|
|
throw new ServiceException($"[交易员支付]单位交易费用 填写错误:{str}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (double.TryParse(str, out var num))
|
|
{
|
|
singleFee = num;
|
|
}
|
|
else
|
|
{
|
|
throw new ServiceException($"[交易员支付]单位交易费用 填写错误:{str}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
td.trade_swap.PaySwapRate = reader.GetPercent("互换利率(年化)", false) ?? 0;
|
|
if (td.trade_swap.PaySwapRate != 0)
|
|
{
|
|
td.trade_swap.PaySwapTimeAndRate = td.ExerciseDate.Value.ToString("yyyy-MM-dd") + ";" + td.trade_swap.PaySwapRate;
|
|
}
|
|
td.trade_swap.PayMarginRate = reader.GetPercent("初始预付金率", false) ?? 0;
|
|
|
|
#endregion
|
|
|
|
if ((string.IsNullOrWhiteSpace(td.trade_swap.GetLongShort) && string.IsNullOrWhiteSpace(td.trade_swap.PayLongShort)) || (!string.IsNullOrWhiteSpace(td.trade_swap.GetLongShort) && !string.IsNullOrWhiteSpace(td.trade_swap.PayLongShort)))
|
|
{
|
|
throw new ServiceException($"注意“交易员收取”和“交易员支付”不可同时为浮动收益或利息收益!");
|
|
}
|
|
|
|
//币种
|
|
var underlyingModel = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
|
|
td.QuoteCurrency = DataCacheProvider.GetVarietyDataSource().GetData(underlyingModel.UnderlyingTypeId).QuoteCurrency;
|
|
|
|
|
|
if (ExchangeRate != null)
|
|
{
|
|
if (td.QuoteCurrency != "CNY" && (!string.IsNullOrEmpty(td.QuoteCurrency)))
|
|
{
|
|
td.MetaDic.Add("ExchangeRate", ExchangeRate.ToString());
|
|
}
|
|
}
|
|
if (td.trade_swap.IsGetFloatingProfit)
|
|
{
|
|
if (!td.trade_swap.IsShare)
|
|
{
|
|
td.trade_swap.PaySingleFee = singleFee * um.ContractSize;
|
|
}
|
|
else
|
|
{
|
|
td.trade_swap.PaySingleFee = singleFee;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!td.trade_swap.IsShare)
|
|
{
|
|
td.trade_swap.GetSingleFee = singleFee * um.ContractSize;
|
|
}
|
|
else
|
|
{
|
|
td.trade_swap.GetSingleFee = singleFee;
|
|
}
|
|
}
|
|
|
|
var variety = DataCacheProvider.GetVariety(td.UnderlyingCode);
|
|
if (variety == null)
|
|
{
|
|
throw new ServiceException($"该标的[{td.UnderlyingCode}]对应的品种在系统中不存在");
|
|
}
|
|
else
|
|
{
|
|
if (string.IsNullOrWhiteSpace(variety.QuoteCurrency) && DbContext.currency.Any())
|
|
{
|
|
throw new ServiceException($"标的代码[{td.UnderlyingCode}]对应的品种币种不能为空");
|
|
}
|
|
else
|
|
{
|
|
td.QuoteCurrency = variety.QuoteCurrency;
|
|
}
|
|
|
|
var market = DataCacheProvider.GetMarketDataSource().AsQueryable().FirstOrDefault(x => x.MarketName == variety.TradingMarket);
|
|
|
|
if (QdpCalendarHelper.IsHoliday((DateTime)td.TradeDate, string.IsNullOrWhiteSpace(market?.CalendarName) ? "chn" : market?.CalendarName))
|
|
{
|
|
throw new ServiceException("成交日期:" + td.TradeDate + ",不能为节假日");
|
|
}
|
|
if (QdpCalendarHelper.IsHoliday((DateTime)td.ExerciseDate, string.IsNullOrWhiteSpace(market?.CalendarName) ? "chn" : market?.CalendarName))
|
|
{
|
|
throw new ServiceException("到期日期:" + td.ExerciseDate + ",不能为节假日");
|
|
}
|
|
if (td.TradeDate > td.ExerciseDate)
|
|
{
|
|
throw new ServiceException("到期日期不能早于成交日期");
|
|
}
|
|
}
|
|
|
|
reader.SetTopType("了结信息");
|
|
var action = reader.GetString("了结方式", false);
|
|
var hasSettleMode = !string.IsNullOrWhiteSpace(action);
|
|
InnerSaveSwapTrade(td, hasSettleMode, false);
|
|
|
|
#region 了结信息
|
|
|
|
|
|
if (hasSettleMode)
|
|
{
|
|
td.UnWindDate = reader.GetDate("了结日期", true);
|
|
|
|
if (action == "互换" && td.UnWindDate != td.ExerciseDate)
|
|
{
|
|
throw new ServiceException($"只支持到期日互换,了结日期[{td.UnWindDate}]和到日期[{td.ExerciseDate}]不一致");
|
|
}
|
|
|
|
td.FinalPrice = reader.GetDouble("了结标的价格", false);
|
|
|
|
var eodpriceProvider = new YLErp.Modules.DataProviderModule.EodPriceProvider((DateTime)td.UnWindDate);
|
|
|
|
if (td.FinalPrice == null)
|
|
{
|
|
td.FinalPrice = eodpriceProvider.GetPrice(td.UnderlyingCode, SettlementTypeEnum.ClosePrice);//平仓当天标的价格;
|
|
}
|
|
|
|
var annualFee = reader.GetDouble("利息金额", false);
|
|
var costFee = reader.GetDouble("平仓手续费", false);
|
|
UnwindSwapTradeCashHandle(td, action, annualFee, costFee);
|
|
}
|
|
|
|
#endregion
|
|
|
|
//记录审核日志
|
|
DbContext.TradeAuditLog.Add(new TradeAuditLog
|
|
{
|
|
TradeId = td.id,
|
|
Changes = null,
|
|
DataType = "00",
|
|
OptId = UserId,
|
|
OptName = UserName,
|
|
OptDate = OptDate,
|
|
OptType = "导入交易",
|
|
AuditFlag = TradeAuditFlag.operation
|
|
});
|
|
DbContext.SaveChanges();
|
|
return td;
|
|
}
|
|
|
|
private trade HandleToEndSwapTrade(DataRowReader reader)
|
|
{
|
|
var tradeNumnr = reader.GetString("交易编号", false);
|
|
var td = new trade();
|
|
var tdTable = DbContext.trade.FirstOrDefault(a => a.TradeNumber == tradeNumnr);
|
|
if (tdTable == null)
|
|
{
|
|
throw new ServiceException($"此交易编号[{td.TradeNumber}]不存在");
|
|
}
|
|
if (tdTable.TradeStatus != ConsTrade.确认成交)
|
|
{
|
|
throw new ServiceException("只有交易状态为‘确认成交’,才能进行批量了结导入");
|
|
}
|
|
|
|
td = tdTable;
|
|
td.trade_cash = new trade_cash();
|
|
td.trade_cash.UnwindStockEqvNotional = reader.GetDouble("了结名义本金", false) ?? 0;
|
|
td.trade_cash.UnwindPercentRate = reader.GetPercent("了结比例", false) ?? 0;
|
|
|
|
if (td.trade_cash.UnwindStockEqvNotional == 0 && td.trade_cash.UnwindPercentRate == 0)
|
|
{
|
|
throw new ServiceException($"交易编号[{td.TradeNumber}]中,了结名义本金与了结比例,必须填写一个值");
|
|
}
|
|
|
|
td.UnWindDate = reader.GetDate("了结日期", true);
|
|
|
|
var variety = DataCacheProvider.GetVariety(td.UnderlyingCode);
|
|
if (variety == null)
|
|
{
|
|
throw new ServiceException($"该标的[{td.UnderlyingCode}]对应的品种在系统中不存在");
|
|
}
|
|
else
|
|
{
|
|
var market = DataCacheProvider.GetMarketDataSource().AsQueryable().FirstOrDefault(x => x.MarketName == variety.TradingMarket);
|
|
if (QdpCalendarHelper.IsHoliday((DateTime)td.UnWindDate, string.IsNullOrWhiteSpace(market?.CalendarName) ? "chn" : market?.CalendarName))
|
|
{
|
|
throw new ServiceException("了结日期:" + td.UnWindDate + ",不能为节假日");
|
|
}
|
|
}
|
|
|
|
if (td.TradeDate > td.UnWindDate)
|
|
{
|
|
throw new ServiceException("了结日期必须要大于或等于成交日期");
|
|
}
|
|
if (td.UnWindDate > td.ExerciseDate)
|
|
{
|
|
throw new ServiceException("了结日期必须要小于或等于到期日期");
|
|
}
|
|
if (td.UnWindDate > valuedateBLL.ValueDate)
|
|
{
|
|
throw new ServiceException("了结日期必须要小于或等于系统日期");
|
|
}
|
|
|
|
td.FinalPrice = reader.GetDouble("了结标的价格", false);
|
|
var annualFeePay = reader.GetDouble("[支付]利息金额", false);
|
|
var annualFeeGet = reader.GetDouble("[收取]利息金额", false);
|
|
var costFee = reader.GetDouble("平仓手续费", false);
|
|
|
|
UnwindSwapTradeCashHandle(td, annualFeeGet, annualFeePay, costFee);
|
|
return td;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 写入交易记录
|
|
/// </summary>
|
|
/// <param name="td">交易记录</param>
|
|
/// <param name="hasSettleMode">是否存在了结方式</param>
|
|
/// <param name="isHistoryImport">是否历史导入</param>
|
|
/// <exception cref="ServiceException"></exception>
|
|
private void InnerSaveSwapTrade(trade td, bool hasSettleMode = true, bool isHistoryImport = true)
|
|
{
|
|
td.TradeStatus = ConsTrade.确认成交;
|
|
if (!isHistoryImport && !hasSettleMode)
|
|
{
|
|
td.TradeStatus = ConsTrade.新增待确认;
|
|
}
|
|
if (string.IsNullOrWhiteSpace(td.TradeNumber))
|
|
{
|
|
td.TradeNumber = BizLogicSingleton.Instance.GenerateTradeNumberBeforeConfirm(td, DbContext);
|
|
}
|
|
else
|
|
{
|
|
if (DbContext.trade.Any(x => x.TradeNumber == td.TradeNumber))
|
|
{
|
|
throw new ServiceException($"存在重复的交易编号[{td.TradeNumber}]");
|
|
}
|
|
}
|
|
|
|
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, td.TradeDate.Value, seekPreday: true);
|
|
var tradePriceQuote = 0.0;
|
|
|
|
if (td.trade_swap.IsPayFloatingProfit)
|
|
{
|
|
tradePriceQuote = ((td.trade_swap.GetSingleFee ?? 0) * (td.Lots ?? 0) + td.StockEqvNotional * (td.trade_swap.GetUnAnnualRate ?? 0)).FormatValue(2);
|
|
td.trade_swap.GetTradePrice = tradePriceQuote;
|
|
if (td.trade_swap.IsTradePriceWhenOpen)
|
|
{
|
|
td.TradePrice = (tradePriceQuote * currencyRate).FormatValue(2);
|
|
}
|
|
else
|
|
{
|
|
tradePriceQuote = 0;
|
|
}
|
|
td.BuySell = "卖出";
|
|
}
|
|
else
|
|
{
|
|
tradePriceQuote = ((td.trade_swap.PaySingleFee ?? 0) * (td.Lots ?? 0) + td.StockEqvNotional * (td.trade_swap.PayUnAnnualRate ?? 0)).FormatValue(2);
|
|
td.trade_swap.PayTradePrice = tradePriceQuote;
|
|
if (td.trade_swap.IsTradePriceWhenOpen)
|
|
{
|
|
td.TradePrice = (tradePriceQuote * currencyRate).FormatValue(2);
|
|
}
|
|
else
|
|
{
|
|
tradePriceQuote = 0;
|
|
}
|
|
td.BuySell = "买入";
|
|
}
|
|
|
|
|
|
td.OriginalNotional = td.Notional;
|
|
td.OriginalStockEqvNotional = td.StockEqvNotional;
|
|
td.StockEqvNotionalReal = td.StockEqvNotionalReal;
|
|
td.IsUsePremiumRate = true;
|
|
td.MarginTemplateName = null;
|
|
td.MarginType = MarginTypeEnum.DEFAULT;
|
|
td.IsTradePricePayType = true;
|
|
td.TradeSource = TradeSourceEnum.导入交易.ToString();
|
|
td.OptId = UserId;
|
|
td.OptName = UserName;
|
|
td.OptDate = DateTime.Now;
|
|
SetDBModelCreator(td);
|
|
DbContext.trade.Add(td);
|
|
DbContext.SaveChanges();
|
|
td.trade_swap.TradeId = td.id;
|
|
td.trade_swap.SwapType = "普通";
|
|
td.trade_swap.OptId = UserId;
|
|
td.trade_swap.OptName = UserName;
|
|
td.trade_swap.OptDate = DateTime.Now;
|
|
DbContext.trade_swap.Add(td.trade_swap);
|
|
|
|
SaveTradeMeta(td);
|
|
|
|
if (isHistoryImport || hasSettleMode)
|
|
{
|
|
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.系统操作_期权费;
|
|
tc.Amount = (td.TradePrice ?? 0) * (td.BuySell == "买入" ? -1 : 1);
|
|
tc.QuoteAmount = tradePriceQuote * (td.BuySell == "买入" ? -1 : 1);
|
|
tc.CurrencyRate = currencyRate;
|
|
tc.ExceciseType = "现金";
|
|
tc.TradeId = td.id;
|
|
tc.ValueDate = td.TradeDate.Value;
|
|
tc.Notional = td.Notional;
|
|
tc.TradeAmount = td.TradeAmount;
|
|
tc.Status = TradeCashStatusEnum.已执行;
|
|
tc.TradeType = td.BuySell;
|
|
DbContext.SaveChanges();
|
|
|
|
new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, 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 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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 了结导入数据处理
|
|
/// </summary>
|
|
/// <param name="td"></param>
|
|
/// <param name="annualFee"></param>
|
|
/// <param name="costFee"></param>
|
|
private void UnwindSwapTradeCashHandle(trade td, double? annualFeeGet, double? annualFeePay, double? costFee)
|
|
{
|
|
var client = DataCacheProvider.GetClientDataSource().GetData(td.ClientId);
|
|
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
|
|
|
|
if (td.FinalPrice == null)
|
|
{
|
|
var eodpriceProvider = new YLErp.Modules.DataProviderModule.EodPriceProvider((DateTime)td.UnWindDate);
|
|
if (eodpriceProvider.TryGetPrice(td.UnderlyingCode, SettlementTypeEnum.ClosePrice, out var price))
|
|
{
|
|
td.FinalPrice = price;
|
|
}
|
|
else
|
|
{
|
|
throw new ServiceException($"未找到{td.UnderlyingCode}在{td.UnWindDate?.ToString("yyyy.M.d")}对应的收盘价");
|
|
}
|
|
}
|
|
|
|
td.trade_swap = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == td.id);
|
|
|
|
var unwindType = "部分平仓";
|
|
//获取平仓比例
|
|
if (td.trade_cash.UnwindPercentRate == 0 || (td.trade_cash.UnwindStockEqvNotional != 0 && td.trade_cash.UnwindPercentRate != 0))
|
|
{
|
|
if (td.StockEqvNotional <= td.trade_cash.UnwindStockEqvNotional + 1e-10)
|
|
{
|
|
td.trade_cash.UnwindStockEqvNotional = td.StockEqvNotional;
|
|
unwindType = "全部平仓";
|
|
}
|
|
td.trade_cash.UnwindPercentRate = td.trade_cash.UnwindStockEqvNotional / td.OriginalStockEqvNotional;
|
|
}
|
|
else if ((td.StockEqvNotional / td.OriginalStockEqvNotional) <= td.trade_cash.UnwindPercentRate + 1e-10)
|
|
{
|
|
td.trade_cash.UnwindPercentRate = td.StockEqvNotional / td.OriginalStockEqvNotional;
|
|
td.trade_cash.UnwindStockEqvNotional = td.StockEqvNotional;
|
|
unwindType = "全部平仓";
|
|
}
|
|
|
|
if (td.trade_cash.UnwindStockEqvNotional == 0)
|
|
{
|
|
if ((td.StockEqvNotional / td.OriginalStockEqvNotional) <= td.trade_cash.UnwindPercentRate + 1e-10)
|
|
{
|
|
td.trade_cash.UnwindPercentRate = td.StockEqvNotional / td.OriginalStockEqvNotional;
|
|
unwindType = "全部平仓";
|
|
}
|
|
td.trade_cash.UnwindStockEqvNotional = (double)(td.OriginalStockEqvNotional * td.trade_cash.UnwindPercentRate);
|
|
}
|
|
else if (td.StockEqvNotional <= td.trade_cash.UnwindStockEqvNotional + 1e-10)
|
|
{
|
|
td.trade_cash.UnwindPercentRate = td.StockEqvNotional / td.OriginalStockEqvNotional;
|
|
td.trade_cash.UnwindStockEqvNotional = td.StockEqvNotional;
|
|
unwindType = "全部平仓";
|
|
}
|
|
|
|
//增加现金交割交易记录
|
|
var tc = new trade_cash();
|
|
|
|
tc.OptId = UserId;
|
|
tc.OptName = UserName;
|
|
tc.OptDate = OptDate;
|
|
tc.ExceciseType = "现金";
|
|
tc.TradeType = td.BuySell;
|
|
tc.CallPut = td.CallPut;
|
|
tc.IsLastAction = true;
|
|
tc.TradeId = td.id;
|
|
tc.FinalPrice = td.FinalPrice;
|
|
tc.Notional = td.Notional;
|
|
tc.TradeAmount = td.TradeAmount;
|
|
tc.UnwindType = unwindType;
|
|
tc.UnwindNotional = td.trade_cash.UnwindPercentRate * td.OriginalNotional;
|
|
tc.UnwindTradeAmount = tc.UnwindNotional / um.CountRatio;
|
|
tc.UnwindPercentRate = td.trade_cash.UnwindPercentRate;
|
|
tc.NotionalPercentRate = tc.UnwindPercentRate;
|
|
|
|
if (td.trade_swap.IsPayFloatingProfit)
|
|
{
|
|
var tradeCashs = DbContext.trade_cash.Where(y => y.TradeId == td.id && y.Action == "系统操作-互换" && y.ValidState != "InValid" && !y.IsDeleted && y.ValueDate <= td.UnWindDate);
|
|
var tradeCashIds = tradeCashs.Select(x => x.id);
|
|
var tradeCash = tradeCashs.OrderByDescending(y => y.id).FirstOrDefault();
|
|
var cashSwaps = DbContext.trade_cash_swap.Where(x => x.TradeId == td.id && tradeCashIds.Contains(x.TradeCashId)).ToArray();
|
|
var tradeCashSwap = tradeCash != null ? cashSwaps.FirstOrDefault(x => x.TradeCashId == tradeCash.id) : null;
|
|
//取最后一次手动收益;
|
|
var lastManualCashSwap = cashSwaps.OrderByDescending(o => o.StartDate).FirstOrDefault(x => !x.IsAuto);
|
|
var lastManualCash = lastManualCashSwap != null ? tradeCashs.FirstOrDefault(x => x.id == lastManualCashSwap.TradeCashId) : null;
|
|
var initialAmountPayQuote = PayoffSwapCalcService.GetInitialAmountSwapPay(td, td.trade_swap, tradeCashSwap?.PayFinalPrice ?? td.SpotPrice ?? 0
|
|
, td.FinalPrice ?? 0, td.trade_cash.UnwindStockEqvNotional ?? 0, td.UnWindDate.Value, tradeCash?.ValueDate);
|
|
DateTime endDate;
|
|
var preSwapDate = PayoffSwapCalcService.GetSwapRateStartDate(td, td.trade_swap, td.UnWindDate.Value, tradeCash, lastManualCash, td.trade_swap.IsGetFloatingProfit, out endDate);
|
|
|
|
var extraAmountGetQuote = annualFeeGet ?? PayoffSwapCalcService.GetExtraAmountBySwapRate(td.ClientId, td.TradeDate, td.trade_swap.GetSwapTimeAndRate, preSwapDate, endDate, td.trade_swap.AnnualDays ?? 0, td.trade_cash.UnwindStockEqvNotional ?? 0);
|
|
|
|
var costFeeGetQuote = costFee ?? 0;
|
|
|
|
var costTradePriceGetQuote = 0.0;
|
|
if (!td.trade_swap.IsTradePriceWhenOpen)
|
|
{
|
|
costTradePriceGetQuote = PayoffSwapCalcService.GetCostFee(td, td, tc, true, true);
|
|
}
|
|
|
|
var quoteAmount = extraAmountGetQuote + costFeeGetQuote + costTradePriceGetQuote - initialAmountPayQuote;
|
|
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, td.UnWindDate.Value, seekPreday: true, currencyRateType: quoteAmount < 0 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
|
|
|
|
var initialAmountPay = (initialAmountPayQuote * currencyRate).FormatValue(2);
|
|
var extraAmountGet = (extraAmountGetQuote * currencyRate).FormatValue(2);
|
|
var costFeeGet = (costFeeGetQuote * currencyRate).FormatValue(2);
|
|
var costTradePriceGet = (costTradePriceGetQuote * currencyRate).FormatValue(2);
|
|
|
|
tc.CurrencyRate = currencyRate;
|
|
tc.Action = ClientCashInCashOut.系统操作_平仓费;
|
|
tc.IsLastAction = td.Notional <= 0 ? true : false;
|
|
tc.Status = TradeCashStatusEnum.已执行;
|
|
tc.ValueDate = td.UnWindDate.Value;
|
|
tc.ValidState = "Valid";
|
|
tc.ExerciseWay = TradeCashExerciseWayEnum.提前终止行权;
|
|
|
|
td.StockEqvNotional -= (double)(td.OriginalStockEqvNotional * tc.UnwindPercentRate);
|
|
td.Notional -= (double)(td.OriginalNotional * tc.UnwindPercentRate);
|
|
td.TradeAmount = td.Notional / um.CountRatio;
|
|
td.UnWindNotional = tc.UnwindNotional;
|
|
td.TradeStatus = tc.ValueDate == td.ExerciseDate ? "已到期" : (tc.UnwindType == "全部平仓" ? "已平仓" : td.TradeStatus);
|
|
td.HasPartialUnWind = tc.UnwindType == "部分平仓" ? 1 : 0;
|
|
|
|
var trade_cash_swap = new trade_cash_swap();
|
|
trade_cash_swap.StartDate = td.StartDate.Value;
|
|
trade_cash_swap.PayStartPrice = td.trade_swap.PayFinalPrice ?? td.trade_swap.PaySpotPrice;
|
|
trade_cash_swap.PayFinalPrice = tc.FinalPrice;
|
|
trade_cash_swap.PayInitialAmount = initialAmountPay;
|
|
trade_cash_swap.PaySwapRate = PayoffSwapCalcService.GetSwapRateByDate(td.trade_swap.PaySwapTimeAndRate, td.UnWindDate.Value);
|
|
|
|
preSwapDate = PayoffSwapCalcService.GetSwapRateStartDate(td, td.trade_swap, td.UnWindDate.Value, tradeCash, lastManualCash, td.trade_swap.IsPayFloatingProfit, out endDate);
|
|
var extraAmountPayQuote = annualFeePay ?? PayoffSwapCalcService.GetExtraAmountBySwapRate(td.ClientId, td.TradeDate, td.trade_swap.PaySwapTimeAndRate, preSwapDate, endDate, td.trade_swap.AnnualDays ?? 0, td.trade_cash.UnwindStockEqvNotional ?? 0);
|
|
var extraAmountPay = (extraAmountPayQuote * currencyRate).FormatValue(2);
|
|
|
|
trade_cash_swap.PayExtraAmount = extraAmountPay;
|
|
trade_cash_swap.PayAmount = trade_cash_swap.PayInitialAmount + extraAmountPay;
|
|
|
|
trade_cash_swap.GetExtraAmount = extraAmountGet;
|
|
trade_cash_swap.GetCostFee = costFeeGet + costTradePriceGet;
|
|
trade_cash_swap.GetAmount = (trade_cash_swap.GetExtraAmount ?? 0) + (trade_cash_swap.GetCostFee ?? 0);
|
|
trade_cash_swap.GetSwapRate = PayoffSwapCalcService.GetSwapRateByDate(td.trade_swap.GetSwapTimeAndRate, td.UnWindDate.Value);
|
|
|
|
tc.Amount = (trade_cash_swap.GetAmount ?? 0) - (trade_cash_swap.PayAmount ?? 0);
|
|
tc.QuoteAmount = tc.Amount;
|
|
DbContext.trade_cash.Add(tc);
|
|
DbContext.SaveChanges();
|
|
|
|
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;
|
|
DbContext.trade_cash_swap.Add(trade_cash_swap);
|
|
DbContext.SaveChanges();
|
|
|
|
var tcdGet = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = extraAmountGet - extraAmountPay,
|
|
QuoteAmount = extraAmountGetQuote - extraAmountPayQuote,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.利息.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdGet);
|
|
|
|
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 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 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);
|
|
}
|
|
else
|
|
{
|
|
var tradeCashs = DbContext.trade_cash.Where(y => y.TradeId == td.id && y.Action == "系统操作-互换" && y.ValidState != "InValid" && !y.IsDeleted && y.ValueDate <= td.UnWindDate);
|
|
var tradeCashIds = tradeCashs.Select(x => x.id);
|
|
var tradeCash = tradeCashs.OrderByDescending(y => y.id).FirstOrDefault();
|
|
var cashSwaps = DbContext.trade_cash_swap.Where(x => x.TradeId == td.id && tradeCashIds.Contains(x.TradeCashId)).ToArray();
|
|
var tradeCashSwap = tradeCash != null ? cashSwaps.FirstOrDefault(x => x.TradeCashId == tradeCash.id) : null;
|
|
//取最后一次手动收益;
|
|
var lastManualCashSwap = cashSwaps.OrderByDescending(o => o.StartDate).FirstOrDefault(x => !x.IsAuto);
|
|
var lastManualCash = lastManualCashSwap != null ? tradeCashs.FirstOrDefault(x => x.id == lastManualCashSwap.TradeCashId) : null;
|
|
var initialAmountGetQuote = PayoffSwapCalcService.GetInitialAmountSwapGet(td, td.trade_swap, tradeCashSwap?.GetFinalPrice ?? td.SpotPrice ?? 0
|
|
, td.FinalPrice ?? 0, td.trade_cash.UnwindStockEqvNotional ?? 0, td.UnWindDate.Value, tradeCash?.ValueDate);
|
|
DateTime endDate;
|
|
var preSwapDate = PayoffSwapCalcService.GetSwapRateStartDate(td, td.trade_swap, td.UnWindDate.Value, tradeCash, lastManualCash, td.trade_swap.IsPayFloatingProfit, out endDate);
|
|
var extraAmountPayQuote = annualFeePay ?? PayoffSwapCalcService.GetExtraAmountBySwapRate(td.ClientId, td.TradeDate, td.trade_swap.PaySwapTimeAndRate, preSwapDate, endDate, td.trade_swap.AnnualDays ?? 0, td.trade_cash.UnwindStockEqvNotional ?? 0);
|
|
|
|
var costFeePayQuote = costFee ?? 0;
|
|
|
|
var costTradePricePayQuote = 0.0;
|
|
if (!td.trade_swap.IsTradePriceWhenOpen)
|
|
{
|
|
costTradePricePayQuote = PayoffSwapCalcService.GetCostFee(td, td, tc, false, true);
|
|
|
|
}
|
|
|
|
var quoteAmount = initialAmountGetQuote - extraAmountPayQuote - costFeePayQuote - costTradePricePayQuote;
|
|
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, td.UnWindDate.Value, seekPreday: true, currencyRateType: quoteAmount < 0 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
|
|
var initialAmountGet = (initialAmountGetQuote * currencyRate).FormatValue(2);
|
|
|
|
var extraAmountPay = (extraAmountPayQuote * currencyRate).FormatValue(2);
|
|
var costFeePay = (costFeePayQuote * currencyRate).FormatValue(2);
|
|
var costTradePricePay = (costTradePricePayQuote * currencyRate).FormatValue(2);
|
|
|
|
tc.CurrencyRate = currencyRate;
|
|
tc.Action = ClientCashInCashOut.系统操作_平仓费;
|
|
tc.IsLastAction = td.Notional <= 0 ? true : false;
|
|
tc.Status = TradeCashStatusEnum.已执行;
|
|
tc.ValueDate = td.UnWindDate.Value;
|
|
tc.ValidState = "Valid";
|
|
tc.ExerciseWay = TradeCashExerciseWayEnum.提前终止行权;
|
|
|
|
td.StockEqvNotional -= (double)(td.OriginalStockEqvNotional * tc.UnwindPercentRate);
|
|
td.Notional -= (double)(td.OriginalNotional * tc.UnwindPercentRate);
|
|
td.TradeAmount = td.Notional / um.CountRatio;
|
|
td.UnWindNotional = tc.UnwindNotional;
|
|
td.TradeStatus = tc.ValueDate == td.ExerciseDate ? "已到期" : (tc.UnwindType == "全部平仓" ? "已平仓" : td.TradeStatus);
|
|
td.HasPartialUnWind = tc.UnwindType == "部分平仓" ? 1 : 0;
|
|
|
|
var trade_cash_swap = new trade_cash_swap();
|
|
trade_cash_swap.StartDate = td.StartDate.Value;
|
|
trade_cash_swap.GetStartPrice = td.trade_swap.GetFinalPrice ?? td.trade_swap.GetSpotPrice;
|
|
trade_cash_swap.GetFinalPrice = tc.FinalPrice;
|
|
trade_cash_swap.GetInitialAmount = initialAmountGet;
|
|
|
|
trade_cash_swap.GetSwapRate = PayoffSwapCalcService.GetSwapRateByDate(td.trade_swap.GetSwapTimeAndRate, td.UnWindDate.Value);
|
|
|
|
preSwapDate = PayoffSwapCalcService.GetSwapRateStartDate(td, td.trade_swap, td.UnWindDate.Value, tradeCash, lastManualCash, td.trade_swap.IsGetFloatingProfit, out endDate);
|
|
var extraAmountGetQuote = annualFeeGet ?? PayoffSwapCalcService.GetExtraAmountBySwapRate(td.ClientId, td.TradeDate, td.trade_swap.GetSwapTimeAndRate, preSwapDate, endDate, td.trade_swap.AnnualDays ?? 0, td.trade_cash.UnwindStockEqvNotional ?? 0);
|
|
var extraAmountGet = (extraAmountGetQuote * currencyRate).FormatValue(2);
|
|
|
|
trade_cash_swap.GetExtraAmount = extraAmountGet;
|
|
trade_cash_swap.GetAmount = initialAmountGet + extraAmountGet;
|
|
|
|
trade_cash_swap.PayExtraAmount = extraAmountPay;
|
|
trade_cash_swap.PayCostFee = costFeePay + costTradePricePay;
|
|
trade_cash_swap.PayAmount = (trade_cash_swap.PayExtraAmount ?? 0) + (trade_cash_swap.PayCostFee ?? 0);
|
|
trade_cash_swap.PaySwapRate = PayoffSwapCalcService.GetSwapRateByDate(td.trade_swap.PaySwapTimeAndRate, td.UnWindDate.Value);
|
|
|
|
tc.Amount = (trade_cash_swap.GetAmount ?? 0) - (trade_cash_swap.PayAmount ?? 0);
|
|
tc.QuoteAmount = tc.Amount;
|
|
DbContext.trade_cash.Add(tc);
|
|
DbContext.SaveChanges();
|
|
|
|
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;
|
|
DbContext.trade_cash_swap.Add(trade_cash_swap);
|
|
DbContext.SaveChanges();
|
|
|
|
var tcdExtraAmount = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = extraAmountGet - extraAmountPay,
|
|
QuoteAmount = extraAmountGetQuote - extraAmountPayQuote,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.利息.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdExtraAmount);
|
|
|
|
var tcdCostFeeGet = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = -costFeePay,
|
|
QuoteAmount = -costFeePayQuote,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.了结手续费.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdCostFeeGet);
|
|
|
|
var tcdCostTradePriceGet = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = -costTradePricePay,
|
|
QuoteAmount = -costTradePricePayQuote,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.开仓手续费.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdCostTradePriceGet);
|
|
|
|
var tcdPay = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = initialAmountGet,
|
|
QuoteAmount = initialAmountGetQuote,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = false,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.浮动收益.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdPay);
|
|
}
|
|
|
|
//增加出入金记录
|
|
new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, tc, tc.ValueDate);
|
|
|
|
var auditLog = new TradeAuditLog
|
|
{
|
|
TradeId = tc.TradeId,
|
|
Changes = null,
|
|
DataType = "00",
|
|
OptType = "批量了结-平仓",
|
|
OptId = UserId,
|
|
OptName = UserName,
|
|
OptDate = OptDate,
|
|
AuditFlag = TradeAuditFlag.operation
|
|
};
|
|
//记录审核日志
|
|
DbContext.TradeAuditLog.Add(auditLog);
|
|
DbContext.SaveChanges();
|
|
}
|
|
private void UnwindSwapTradeCashHandle(trade td, string action, double? annualFee, double? costFee)
|
|
{
|
|
var client = DataCacheProvider.GetClientDataSource().GetData(td.ClientId);
|
|
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
|
|
|
|
//增加现金交割交易记录
|
|
var tc = new trade_cash();
|
|
DbContext.trade_cash.Add(tc);
|
|
|
|
tc.OptId = UserId;
|
|
tc.OptName = UserName;
|
|
tc.OptDate = OptDate;
|
|
tc.ExceciseType = "现金";
|
|
tc.TradeType = td.BuySell;
|
|
tc.CallPut = td.CallPut;
|
|
tc.Notional = td.Notional;
|
|
tc.TradeAmount = td.TradeAmount;
|
|
tc.IsLastAction = true;
|
|
tc.TradeId = td.id;
|
|
tc.FinalPrice = td.FinalPrice;
|
|
tc.UnwindType = "全部平仓";
|
|
tc.UnwindNotional = td.Notional;
|
|
tc.UnwindTradeAmount = td.TradeAmount;
|
|
tc.UnwindPercentRate = 1;
|
|
tc.NotionalPercentRate = tc.UnwindPercentRate;
|
|
|
|
if (td.trade_swap.IsPayFloatingProfit)
|
|
{
|
|
var tradeCashs = DbContext.trade_cash.Where(y => y.TradeId == td.id && y.Action == "系统操作-互换" && y.ValidState != "InValid" && !y.IsDeleted && y.ValueDate <= td.UnWindDate);
|
|
var tradeCashIds = tradeCashs.Select(x => x.id);
|
|
var tradeCash = tradeCashs.OrderByDescending(y => y.id).FirstOrDefault();
|
|
var cashSwaps = DbContext.trade_cash_swap.Where(x => x.TradeId == td.id && tradeCashIds.Contains(x.TradeCashId)).ToArray();
|
|
var tradeCashSwap = tradeCash != null ? cashSwaps.FirstOrDefault(x => x.TradeCashId == tradeCash.id) : null;
|
|
//取最后一次手动收益;
|
|
var lastManualCashSwap = cashSwaps.OrderByDescending(o => o.StartDate).FirstOrDefault(x => !x.IsAuto);
|
|
var lastManualCash = lastManualCashSwap != null ? tradeCashs.FirstOrDefault(x => x.id == lastManualCashSwap.TradeCashId) : null;
|
|
var initialAmountPayQuote = PayoffSwapCalcService.GetInitialAmountSwapPay(td, td.trade_swap, tradeCashSwap?.PayFinalPrice ?? td.SpotPrice ?? 0
|
|
, td.FinalPrice ?? 0, (td.OriginalStockEqvNotional ?? 0) * (tc.UnwindPercentRate ?? 0), td.UnWindDate.Value, tradeCash?.ValueDate);
|
|
DateTime endDate;
|
|
var preSwapDate = PayoffSwapCalcService.GetSwapRateStartDate(td, td.trade_swap, td.UnWindDate.Value, tradeCash, lastManualCash, td.trade_swap.IsGetFloatingProfit, out endDate);
|
|
var extraAmountGetQuote = annualFee ?? PayoffSwapCalcService.GetExtraAmountBySwapRate(td.ClientId, td.TradeDate, td.trade_swap.GetSwapTimeAndRate, preSwapDate, endDate, td.trade_swap.AnnualDays ?? 0, (td.OriginalStockEqvNotional ?? 0) * (tc.UnwindPercentRate ?? 0));
|
|
|
|
preSwapDate = PayoffSwapCalcService.GetSwapRateStartDate(td, td.trade_swap, td.UnWindDate.Value, tradeCash, lastManualCash, td.trade_swap.IsPayFloatingProfit, out endDate);
|
|
var extraAmountPayQuote = annualFee ?? PayoffSwapCalcService.GetExtraAmountBySwapRate(td.ClientId, td.TradeDate, td.trade_swap.PaySwapTimeAndRate, preSwapDate, endDate, td.trade_swap.AnnualDays ?? 0, (td.OriginalStockEqvNotional ?? 0) * (tc.UnwindPercentRate ?? 0));
|
|
|
|
var costFeeGetQuote = costFee ?? 0;
|
|
|
|
var costTradePriceGetQuote = 0.0;
|
|
if (!td.trade_swap.IsTradePriceWhenOpen)
|
|
{
|
|
costTradePriceGetQuote = PayoffSwapCalcService.GetCostFee(td, td, tc, true, true);
|
|
}
|
|
|
|
var quoteAmount = extraAmountGetQuote + costFeeGetQuote + costTradePriceGetQuote - initialAmountPayQuote - extraAmountPayQuote;
|
|
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, td.UnWindDate.Value, seekPreday: true, currencyRateType: quoteAmount < 0 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
|
|
|
|
var extraAmountPay = (extraAmountPayQuote * currencyRate).FormatValue(2);
|
|
var initialAmountPay = (initialAmountPayQuote * currencyRate).FormatValue(2);
|
|
var extraAmountGet = (extraAmountGetQuote * currencyRate).FormatValue(2);
|
|
var costFeeGet = (costFeeGetQuote * currencyRate).FormatValue(2);
|
|
var costTradePriceGet = (costTradePriceGetQuote * currencyRate).FormatValue(2);
|
|
|
|
td.TradeStatus = td.UnWindDate.Value == td.ExerciseDate ? "已到期" : "已平仓";
|
|
td.StockEqvNotional = 0;
|
|
td.Notional = 0;
|
|
td.TradeAmount = 0;
|
|
td.UnWindNotional = tc.UnwindNotional;
|
|
|
|
tc.Amount = extraAmountGet + costFeeGet + costTradePriceGet - initialAmountPay - extraAmountPay;
|
|
tc.QuoteAmount = quoteAmount;
|
|
tc.CurrencyRate = currencyRate;
|
|
tc.Action = action == "平仓" ? ClientCashInCashOut.系统操作_平仓费 : ClientCashInCashOut.系统操作_互换;
|
|
tc.IsLastAction = true;
|
|
tc.Status = TradeCashStatusEnum.已执行;
|
|
tc.ValueDate = td.UnWindDate.Value;
|
|
tc.ValidState = "Valid";
|
|
tc.ExerciseWay = td.UnWindDate == td.ExerciseDate ? TradeCashExerciseWayEnum.到期行权 : TradeCashExerciseWayEnum.提前终止行权;
|
|
DbContext.SaveChanges();
|
|
|
|
|
|
//增加出入金记录
|
|
new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, tc, tc.ValueDate);
|
|
|
|
var trade_swap = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == tc.TradeId);
|
|
var trade_cash_swap = new trade_cash_swap();
|
|
trade_cash_swap.StartDate = td.StartDate.Value;
|
|
trade_cash_swap.PayStartPrice = trade_swap.PayFinalPrice ?? trade_swap.PaySpotPrice;
|
|
trade_cash_swap.PayFinalPrice = tc.FinalPrice;
|
|
trade_cash_swap.PayExtraAmount = extraAmountPay;
|
|
trade_cash_swap.PayInitialAmount = initialAmountPay;
|
|
trade_cash_swap.PayAmount = extraAmountPay + initialAmountPay;
|
|
trade_cash_swap.PaySwapRate = PayoffSwapCalcService.GetSwapRateByDate(td.trade_swap.PaySwapTimeAndRate, td.UnWindDate.Value);
|
|
trade_cash_swap.GetExtraAmount = extraAmountGet;
|
|
trade_cash_swap.GetCostFee = costFeeGet + costTradePriceGet;
|
|
trade_cash_swap.GetAmount = extraAmountGet + costFeeGet + costTradePriceGet;
|
|
trade_cash_swap.GetSwapRate = PayoffSwapCalcService.GetSwapRateByDate(td.trade_swap.GetSwapTimeAndRate, td.UnWindDate.Value);
|
|
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;
|
|
DbContext.trade_cash_swap.Add(trade_cash_swap);
|
|
|
|
var tcdExtraAmount = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = extraAmountGet - extraAmountPay,
|
|
QuoteAmount = extraAmountGetQuote - extraAmountPayQuote,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.利息.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdExtraAmount);
|
|
|
|
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 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 tcdInitialAmountPay = 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(tcdInitialAmountPay);
|
|
}
|
|
else
|
|
{
|
|
var tradeCashs = DbContext.trade_cash.Where(y => y.TradeId == td.id && y.Action == "系统操作-互换" && y.ValidState != "InValid" && !y.IsDeleted && y.ValueDate <= td.UnWindDate);
|
|
var tradeCashIds = tradeCashs.Select(x => x.id);
|
|
var tradeCash = tradeCashs.OrderByDescending(y => y.id).FirstOrDefault();
|
|
var cashSwaps = DbContext.trade_cash_swap.Where(x => x.TradeId == td.id && tradeCashIds.Contains(x.TradeCashId)).ToArray();
|
|
var tradeCashSwap = tradeCash != null ? cashSwaps.FirstOrDefault(x => x.TradeCashId == tradeCash.id) : null;
|
|
//取最后一次手动收益;
|
|
var lastManualCashSwap = cashSwaps.OrderByDescending(o => o.StartDate).FirstOrDefault(x => !x.IsAuto);
|
|
var lastManualCash = lastManualCashSwap != null ? tradeCashs.FirstOrDefault(x => x.id == lastManualCashSwap.TradeCashId) : null;
|
|
var initialAmountGetQuote = PayoffSwapCalcService.GetInitialAmountSwapGet(td, td.trade_swap, tradeCashSwap?.GetFinalPrice ?? td.SpotPrice ?? 0
|
|
, td.FinalPrice ?? 0, td.OriginalStockEqvNotional ?? 0, td.UnWindDate.Value, tradeCash?.ValueDate);
|
|
DateTime endDate;
|
|
var preSwapDate = PayoffSwapCalcService.GetSwapRateStartDate(td, td.trade_swap, td.UnWindDate.Value, tradeCash, lastManualCash, td.trade_swap.IsPayFloatingProfit, out endDate);
|
|
var extraAmountPayQuote = annualFee ?? PayoffSwapCalcService.GetExtraAmountBySwapRate(td.ClientId, td.TradeDate, td.trade_swap.PaySwapTimeAndRate, preSwapDate, endDate, td.trade_swap.AnnualDays ?? 0, (td.OriginalStockEqvNotional ?? 0) * (tc.UnwindPercentRate ?? 0));
|
|
|
|
preSwapDate = PayoffSwapCalcService.GetSwapRateStartDate(td, td.trade_swap, td.UnWindDate.Value, tradeCash, lastManualCash, td.trade_swap.IsGetFloatingProfit, out endDate);
|
|
var extraAmountGetQuote = annualFee ?? PayoffSwapCalcService.GetExtraAmountBySwapRate(td.ClientId, td.TradeDate, td.trade_swap.GetSwapTimeAndRate, preSwapDate, endDate, td.trade_swap.AnnualDays ?? 0, (td.OriginalStockEqvNotional ?? 0) * (tc.UnwindPercentRate ?? 0));
|
|
|
|
var costFeePayQuote = costFee ?? 0;
|
|
|
|
var costTradePricePayQuote = 0.0;
|
|
if (!td.trade_swap.IsTradePriceWhenOpen)
|
|
{
|
|
costTradePricePayQuote = PayoffSwapCalcService.GetCostFee(td, td, tc, false, true);
|
|
|
|
}
|
|
|
|
var quoteAmount = initialAmountGetQuote + extraAmountGetQuote - extraAmountPayQuote - costFeePayQuote - costTradePricePayQuote;
|
|
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, td.UnWindDate.Value, seekPreday: true, currencyRateType: quoteAmount < 0 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
|
|
|
|
var extraAmountGet = (extraAmountGetQuote * currencyRate).FormatValue(2);
|
|
var initialAmountGet = (initialAmountGetQuote * currencyRate).FormatValue(2);
|
|
var extraAmountPay = (extraAmountPayQuote * currencyRate).FormatValue(2);
|
|
var costFeePay = (costFeePayQuote * currencyRate).FormatValue(2);
|
|
var costTradePricePay = (costTradePricePayQuote * currencyRate).FormatValue(2);
|
|
|
|
tc.Amount = initialAmountGet + extraAmountGet - extraAmountPay - costFeePay - costTradePricePay;
|
|
tc.QuoteAmount = quoteAmount;
|
|
tc.CurrencyRate = currencyRate;
|
|
tc.Action = action == "平仓" ? ClientCashInCashOut.系统操作_平仓费 : ClientCashInCashOut.系统操作_互换;
|
|
tc.IsLastAction = true;
|
|
tc.Status = TradeCashStatusEnum.已执行;
|
|
tc.ValueDate = td.UnWindDate.Value;
|
|
tc.ValidState = "Valid";
|
|
tc.ExerciseWay = td.UnWindDate == td.ExerciseDate ? TradeCashExerciseWayEnum.到期行权 : TradeCashExerciseWayEnum.提前终止行权;
|
|
DbContext.SaveChanges();
|
|
|
|
td.TradeStatus = tc.ValueDate == td.ExerciseDate ? "已到期" : "已平仓";
|
|
td.StockEqvNotional = 0;
|
|
td.Notional = 0;
|
|
td.TradeAmount = 0;
|
|
td.UnWindNotional = tc.UnwindNotional;
|
|
//增加出入金记录
|
|
new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, tc, tc.ValueDate);
|
|
|
|
var trade_swap = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == tc.TradeId);
|
|
var trade_cash_swap = new trade_cash_swap();
|
|
trade_cash_swap.StartDate = td.StartDate.Value;
|
|
trade_cash_swap.GetStartPrice = trade_swap.GetFinalPrice ?? trade_swap.GetSpotPrice;
|
|
trade_cash_swap.GetFinalPrice = tc.FinalPrice;
|
|
trade_cash_swap.GetInitialAmount = initialAmountGet;
|
|
trade_cash_swap.GetExtraAmount = extraAmountGet;
|
|
trade_cash_swap.GetAmount = initialAmountGet + extraAmountGet;
|
|
trade_cash_swap.GetSwapRate = PayoffSwapCalcService.GetSwapRateByDate(td.trade_swap.GetSwapTimeAndRate, td.UnWindDate.Value);
|
|
trade_cash_swap.PayExtraAmount = extraAmountPay;
|
|
trade_cash_swap.PayCostFee = costFeePay + costTradePricePay;
|
|
trade_cash_swap.PayAmount = extraAmountPay + costFeePay + costTradePricePay;
|
|
trade_cash_swap.PaySwapRate = PayoffSwapCalcService.GetSwapRateByDate(td.trade_swap.PaySwapTimeAndRate, td.UnWindDate.Value);
|
|
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;
|
|
DbContext.trade_cash_swap.Add(trade_cash_swap);
|
|
|
|
var tcdExtraAmount = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = extraAmountGet - extraAmountPay,
|
|
QuoteAmount = extraAmountGetQuote - extraAmountPayQuote,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.利息.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdExtraAmount);
|
|
|
|
var tcdCostFeePay = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = -costFeePay,
|
|
QuoteAmount = -costFeePayQuote,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.了结手续费.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdCostFeePay);
|
|
|
|
var tcdCostTradePricePay = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = -costTradePricePay,
|
|
QuoteAmount = -costTradePricePayQuote,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.开仓手续费.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdCostTradePricePay);
|
|
|
|
var tcdInitialAmountGet = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = initialAmountGet,
|
|
QuoteAmount = initialAmountGetQuote,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = false,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.浮动收益.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdInitialAmountGet);
|
|
}
|
|
|
|
DbContext.SaveChanges();
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region 互换交易历史导入
|
|
/// <summary>
|
|
/// 导入交易
|
|
/// </summary>
|
|
/// <param name="streamIn"></param>
|
|
/// <param name="totalNum">当前文件中的目标期权总条数</param>
|
|
/// <param name="successNum">成功入库的数量</param>
|
|
public void ImportSwapTradeHistroyDataFromExcel(Stream streamIn, out int totalNum, out int successNum)
|
|
{
|
|
totalNum = 0;
|
|
successNum = 0;
|
|
|
|
var rowIndex = 0;
|
|
var groupTradeList = new List<OtcOptionTradeFullEx>();
|
|
var structureTradeList = new List<OtcOptionTradeFullEx>();
|
|
|
|
try
|
|
{
|
|
var ds = Office.ExcelHelper.ReadExcelAsDataSet(streamIn, new[] { 0 }, 0);
|
|
|
|
if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 3)
|
|
{
|
|
throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" };
|
|
}
|
|
|
|
var table = ds.Tables[0];
|
|
var reader = new DataRowTopTypeReader(table);
|
|
|
|
rowIndex = 2;
|
|
totalNum = table.Rows.Count - rowIndex;
|
|
|
|
foreach (var row in table.Rows.Cast<DataRow>().Skip(2))
|
|
{
|
|
using (var trans = BeginTransaction())
|
|
{
|
|
rowIndex++;
|
|
|
|
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
|
|
{
|
|
totalNum--;
|
|
continue;
|
|
}
|
|
|
|
reader.SetDataRow(row);
|
|
|
|
//映射导入数据到交易对象
|
|
HandleSwapTradeHistroyData(reader);
|
|
|
|
successNum++;
|
|
|
|
trans.Commit();
|
|
}
|
|
}
|
|
}
|
|
catch (ServiceException se)
|
|
{
|
|
if (se.Tag != null)
|
|
{
|
|
throw;
|
|
}
|
|
|
|
throw new ServiceException($"已成功导入{successNum}条;\n第{rowIndex}行,{se.Message}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogFactory.GetLogger("导入期权交易").Error(ex);
|
|
throw new ServiceException($"已成功导入{successNum}条,\n第{rowIndex}行,发生错误:{ex.Message}", ex);
|
|
}
|
|
}
|
|
|
|
private trade HandleSwapTradeHistroyData(DataRowTopTypeReader reader)
|
|
{
|
|
var td = new trade();
|
|
td.trade_swap = new trade_swap();
|
|
//基本要素
|
|
td.TradeNumber = reader.GetString("交易编号", false);
|
|
|
|
td.AssetBookName = reader.GetString("簿记账户名称", true);
|
|
td.TraderName = reader.GetString("交易员名称", true);
|
|
new OtcOptionSaveChecker(this).CheckAssetBook(td).CheckTrader(td);
|
|
|
|
td.TradeType = "收益互换";
|
|
td.ClientName = reader.GetString("交易对手方名称", true);
|
|
|
|
if (string.IsNullOrWhiteSpace(td.ClientName))
|
|
{
|
|
throw new ServiceException("交易对手方名称 必须填写");
|
|
}
|
|
|
|
//交易日期
|
|
td.TradeDate = reader.GetDate("成交日期", true);
|
|
td.StartDate = reader.GetDate("开始日期", true);
|
|
td.ExerciseDate = reader.GetDate("到期日期", true);
|
|
td.SettlementDate = td.ExerciseDate;
|
|
|
|
td.StockEqvNotional = reader.GetDouble("名义本金", true) ?? 0;
|
|
td.trade_swap.AnnualDays = reader.GetInt("年化天数", true);
|
|
td.trade_swap.AnnualVarIncome = reader.GetString("浮动收益年化", true) == "是";
|
|
td.trade_swap.RateCalcMode = GetRateCalcMode(reader.GetString("计息方式", true));
|
|
td.trade_swap.IsTradePriceWhenOpen = reader.GetString("是否开仓时收取开仓费", true) == "是";
|
|
td.trade_swap.IsShare = reader.GetString("收费基本单位", true) == "手数";
|
|
var ExchangeRate = reader.GetDouble("汇率", false);
|
|
td.Comments = reader.GetString("备注", false);
|
|
|
|
var clientQuery = DbContextFactory.GetClientDbContext(OptUser).client.AsQueryable();
|
|
if (!string.IsNullOrWhiteSpace(td.ClientName))
|
|
{
|
|
clientQuery = clientQuery.Where(c => c.Name == td.ClientName);
|
|
}
|
|
var client = clientQuery.Select(n => new { n.id, n.SettlementCurrency }).FirstOrDefault();
|
|
|
|
if (client == null)
|
|
{
|
|
throw new ServiceException($"交易对手方不存在,客户名称:{td.ClientName}");
|
|
}
|
|
|
|
td.ClientId = client.id;
|
|
td.SettlementCurrency = client.SettlementCurrency;
|
|
|
|
td.OpponentRole = "乙方";
|
|
|
|
var um = new underlying_manager();
|
|
var singleFee = 0.0;
|
|
|
|
#region 交易员收取信息读取
|
|
|
|
reader.SetTopType("交易员收取");
|
|
td.trade_swap.GetLongShort = reader.GetString("多头空头", false);
|
|
if (!string.IsNullOrWhiteSpace(td.trade_swap.GetLongShort))
|
|
{
|
|
td.trade_swap.IsGetFloatingProfit = true;
|
|
td.trade_swap.GetUnderlyingCode = reader.GetString("标的代码", true);
|
|
|
|
um = DataCacheProvider.GetUnderlyingDataSource().GetData(td.trade_swap.GetUnderlyingCode);
|
|
if (um == null)
|
|
{
|
|
throw new ServiceException($"{td.trade_swap.GetUnderlyingCode} 不存在,请先新建标的再导入");
|
|
}
|
|
|
|
td.trade_swap.GetUnderlyingId = um.id;
|
|
td.UnderlyingId = um.id;
|
|
td.UnderlyingCode = um.UnderlyingCode;
|
|
td.UnderlyingName = um.UnderlyingName;
|
|
td.UnderlyingInstrumentType = um.UnderlyingInstrumentType;
|
|
|
|
if (!td.trade_swap.IsShare)
|
|
{
|
|
td.trade_swap.GetNotional = reader.GetDouble("份额/手数", true);
|
|
td.trade_swap.GetTradeAmount = td.trade_swap.GetNotional / um.CountRatio;
|
|
td.trade_swap.GetLot = td.trade_swap.GetNotional / um.ContractSize;
|
|
}
|
|
else
|
|
{
|
|
td.trade_swap.GetLot = reader.GetDouble("份额/手数", true);
|
|
td.trade_swap.GetNotional = td.trade_swap.GetLot * um.ContractSize;
|
|
td.trade_swap.GetTradeAmount = td.trade_swap.GetNotional / um.CountRatio;
|
|
}
|
|
|
|
td.Notional = td.trade_swap.GetNotional ?? 0;
|
|
td.TradeAmount = td.trade_swap.GetTradeAmount ?? 0;
|
|
td.Lots = td.trade_swap.GetLot;
|
|
|
|
//判断是否组合标的
|
|
var synthetic = DataCacheProvider.GetUnderlyingDataSource().GetSyntheticUnderlying(um.UnderlyingCode);
|
|
//读取组合标的
|
|
if (synthetic != null)
|
|
{
|
|
reader.SetTopType("组合标的");
|
|
var sulist = new List<UnderlyingPriceModel>(4);
|
|
var model = synthetic.GetSyntheticPriceModel();
|
|
var codeSet = model.SuList.Select(n => n.UnderlyingCode).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
for (var i = 1; i <= 4; i++)
|
|
{
|
|
var code = reader.GetString("标的" + i + "_代码");
|
|
if (string.IsNullOrWhiteSpace(code))
|
|
{
|
|
continue;
|
|
}
|
|
if (!codeSet.Remove(code))
|
|
{
|
|
throw new ServiceException($"[组合标的]标的{i}_代码 填写错误,组合标的中不存在此标的:{code}");
|
|
}
|
|
model.SuList.First(n => n.UnderlyingCode.Equals(code, StringComparison.OrdinalIgnoreCase)).Price = reader.GetDouble("标的" + i + "_价格", true).Value;
|
|
}
|
|
if (codeSet.Any())
|
|
{
|
|
throw new ServiceException("[组合标的]未填写完整");
|
|
}
|
|
td.trade_swap.GetSpotPrice = model.Price = model.SuList.Sum(n => n.Coefficient * n.Price) + model.Constant;
|
|
td.MetaDic["组合标的"] = JsonHelper.ToJson(model);
|
|
}
|
|
else
|
|
{
|
|
td.trade_swap.GetSpotPrice = reader.GetDouble("期初标的价格", true);
|
|
}
|
|
td.SpotPrice = td.trade_swap.GetSpotPrice;
|
|
}
|
|
else
|
|
{
|
|
var str = reader.GetString("单位交易费用", true);
|
|
|
|
if (!string.IsNullOrWhiteSpace(str))
|
|
{
|
|
var percent = str.EndsWith("%");
|
|
|
|
if (percent)
|
|
{
|
|
var strTrim = str.TrimEnd('%');
|
|
if (double.TryParse(strTrim, out var num))
|
|
{
|
|
td.trade_swap.GetUnAnnualRate = num / 100;
|
|
}
|
|
else
|
|
{
|
|
throw new ServiceException($"[交易员收取]单位交易费用 填写错误:{str}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (double.TryParse(str, out var num))
|
|
{
|
|
singleFee = num;
|
|
}
|
|
else
|
|
{
|
|
throw new ServiceException($"[交易员收取]单位交易费用 填写错误:{str}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
td.trade_swap.GetSwapRate = reader.GetPercent("互换利率(年化)", false) ?? 0;
|
|
if (td.trade_swap.GetSwapRate >= 0)
|
|
{
|
|
td.trade_swap.GetSwapTimeAndRate = td.ExerciseDate + ";" + td.trade_swap.GetSwapRate;
|
|
}
|
|
td.trade_swap.GetMarginRate = reader.GetPercent("初始预付金率", false) ?? 0;
|
|
|
|
#endregion
|
|
|
|
#region 交易员支付信息读取
|
|
|
|
reader.SetTopType("交易员支付");
|
|
td.trade_swap.PayLongShort = reader.GetString("多头空头", false);
|
|
if (!string.IsNullOrWhiteSpace(td.trade_swap.PayLongShort))
|
|
{
|
|
td.trade_swap.IsPayFloatingProfit = true;
|
|
td.trade_swap.PayUnderlyingCode = reader.GetString("标的代码", true);
|
|
|
|
um = DataCacheProvider.GetUnderlyingDataSource().GetData(td.trade_swap.PayUnderlyingCode);
|
|
if (um == null)
|
|
{
|
|
throw new ServiceException($"{td.trade_swap.PayUnderlyingCode} 不存在,请先新建标的再导入");
|
|
}
|
|
|
|
td.trade_swap.PayUnderlyingId = um.id;
|
|
td.UnderlyingId = um.id;
|
|
td.UnderlyingCode = um.UnderlyingCode;
|
|
td.UnderlyingName = um.UnderlyingName;
|
|
td.UnderlyingInstrumentType = um.UnderlyingInstrumentType;
|
|
|
|
if (!td.trade_swap.IsShare)
|
|
{
|
|
td.trade_swap.PayNotional = reader.GetDouble("份额/手数", true);
|
|
td.trade_swap.PayTradeAmount = td.trade_swap.PayNotional / um.CountRatio;
|
|
td.trade_swap.PayLot = td.trade_swap.PayNotional / um.ContractSize;
|
|
}
|
|
else
|
|
{
|
|
td.trade_swap.PayLot = reader.GetDouble("份额/手数", true);
|
|
td.trade_swap.PayNotional = td.trade_swap.PayLot * um.ContractSize;
|
|
td.trade_swap.PayTradeAmount = td.trade_swap.PayNotional / um.CountRatio;
|
|
}
|
|
|
|
td.Notional = td.trade_swap.PayNotional ?? 0;
|
|
td.TradeAmount = td.trade_swap.PayTradeAmount ?? 0;
|
|
td.Lots = td.trade_swap.PayLot;
|
|
|
|
|
|
//判断是否组合标的
|
|
var synthetic = DataCacheProvider.GetUnderlyingDataSource().GetSyntheticUnderlying(um.UnderlyingCode);
|
|
//读取组合标的
|
|
if (synthetic != null)
|
|
{
|
|
reader.SetTopType("组合标的");
|
|
var sulist = new List<UnderlyingPriceModel>(4);
|
|
var model = synthetic.GetSyntheticPriceModel();
|
|
var codeSet = model.SuList.Select(n => n.UnderlyingCode).ToHashSet(StringComparer.OrdinalIgnoreCase);
|
|
for (var i = 1; i <= 4; i++)
|
|
{
|
|
var code = reader.GetString("标的" + i + "_代码");
|
|
if (string.IsNullOrWhiteSpace(code))
|
|
{
|
|
continue;
|
|
}
|
|
if (!codeSet.Remove(code))
|
|
{
|
|
throw new ServiceException($"[组合标的]标的{i}_代码 填写错误,组合标的中不存在此标的:{code}");
|
|
}
|
|
model.SuList.First(n => n.UnderlyingCode.Equals(code, StringComparison.OrdinalIgnoreCase)).Price = reader.GetDouble("标的" + i + "_价格", true).Value;
|
|
}
|
|
if (codeSet.Any())
|
|
{
|
|
throw new ServiceException("[组合标的]未填写完整");
|
|
}
|
|
td.trade_swap.PaySpotPrice = model.Price = model.SuList.Sum(n => n.Coefficient * n.Price) + model.Constant;
|
|
td.MetaDic["组合标的2"] = JsonHelper.ToJson(model);
|
|
}
|
|
else
|
|
{
|
|
td.trade_swap.PaySpotPrice = reader.GetDouble("期初标的价格", true);
|
|
}
|
|
td.SpotPrice = td.trade_swap.PaySpotPrice;
|
|
}
|
|
else
|
|
{
|
|
var str = reader.GetString("单位交易费用", true);
|
|
|
|
if (!string.IsNullOrWhiteSpace(str))
|
|
{
|
|
var percent = str.EndsWith("%");
|
|
|
|
if (percent)
|
|
{
|
|
var strTrim = str.TrimEnd('%');
|
|
if (double.TryParse(strTrim, out var num))
|
|
{
|
|
td.trade_swap.PayUnAnnualRate = num / 100;
|
|
}
|
|
else
|
|
{
|
|
throw new ServiceException($"[交易员支付]单位交易费用 填写错误:{str}");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (double.TryParse(str, out var num))
|
|
{
|
|
singleFee = num;
|
|
}
|
|
else
|
|
{
|
|
throw new ServiceException($"[交易员支付]单位交易费用 填写错误:{str}");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
td.trade_swap.PaySwapRate = reader.GetPercent("互换利率(年化)", false) ?? 0;
|
|
if (td.trade_swap.PaySwapRate >= 0)
|
|
{
|
|
td.trade_swap.PaySwapTimeAndRate = td.ExerciseDate + ";" + td.trade_swap.PaySwapRate;
|
|
}
|
|
td.trade_swap.PayMarginRate = reader.GetPercent("初始预付金率", false) ?? 0;
|
|
|
|
#endregion
|
|
if ((string.IsNullOrWhiteSpace(td.trade_swap.GetLongShort) && string.IsNullOrWhiteSpace(td.trade_swap.PayLongShort))||(!string.IsNullOrWhiteSpace(td.trade_swap.GetLongShort) && !string.IsNullOrWhiteSpace(td.trade_swap.PayLongShort)))
|
|
{
|
|
throw new ServiceException($"注意“交易员收取”和“交易员支付”不可同时为浮动收益或利息收益!");
|
|
}
|
|
|
|
var underlyingModel = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
|
|
td.QuoteCurrency = DataCacheProvider.GetVarietyDataSource().GetData(underlyingModel.UnderlyingTypeId).QuoteCurrency;
|
|
|
|
if (ExchangeRate != null)
|
|
{
|
|
if (td.QuoteCurrency != "CNY" && (!string.IsNullOrEmpty(td.QuoteCurrency)))
|
|
{
|
|
td.MetaDic.Add("ExchangeRate", ExchangeRate.ToString());
|
|
}
|
|
}
|
|
if (td.trade_swap.IsGetFloatingProfit)
|
|
{
|
|
if (!td.trade_swap.IsShare)
|
|
{
|
|
td.trade_swap.PaySingleFee = singleFee * um.ContractSize;
|
|
}
|
|
else
|
|
{
|
|
td.trade_swap.PaySingleFee = singleFee;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!td.trade_swap.IsShare)
|
|
{
|
|
td.trade_swap.GetSingleFee = singleFee * um.ContractSize;
|
|
}
|
|
else
|
|
{
|
|
td.trade_swap.GetSingleFee = singleFee;
|
|
}
|
|
}
|
|
|
|
var variety = DataCacheProvider.GetVariety(td.UnderlyingCode);
|
|
if (variety == null)
|
|
{
|
|
throw new ServiceException($"该标的[{td.UnderlyingCode}]对应的品种在系统中不存在");
|
|
}
|
|
else
|
|
{
|
|
if (string.IsNullOrWhiteSpace(variety.QuoteCurrency) && DbContext.currency.Any())
|
|
{
|
|
throw new ServiceException($"标的代码[{td.UnderlyingCode}]对应的品种币种不能为空");
|
|
}
|
|
else
|
|
{
|
|
td.QuoteCurrency = variety.QuoteCurrency;
|
|
}
|
|
|
|
var market = DataCacheProvider.GetMarketDataSource().AsQueryable().FirstOrDefault(x => x.MarketName == variety.TradingMarket);
|
|
|
|
if (QdpCalendarHelper.IsHoliday((DateTime)td.TradeDate, string.IsNullOrWhiteSpace(market?.CalendarName) ? "chn" : market?.CalendarName))
|
|
{
|
|
throw new ServiceException("成交日期:" + td.TradeDate + ",不能为节假日");
|
|
}
|
|
if (QdpCalendarHelper.IsHoliday((DateTime)td.ExerciseDate, string.IsNullOrWhiteSpace(market?.CalendarName) ? "chn" : market?.CalendarName))
|
|
{
|
|
throw new ServiceException("到期日期:" + td.ExerciseDate + ",不能为节假日");
|
|
}
|
|
if (td.TradeDate > td.ExerciseDate)
|
|
{
|
|
throw new ServiceException("到期日期不能早于成交日期");
|
|
}
|
|
}
|
|
|
|
InnerSaveSwapTrade(td);
|
|
|
|
#region 了结信息
|
|
|
|
reader.SetTopType("了结信息");
|
|
var action = reader.GetString("了结方式", false);
|
|
if (!string.IsNullOrWhiteSpace(action))
|
|
{
|
|
td.UnWindDate = reader.GetDate("了结日期", true);
|
|
|
|
if (action == "互换" && td.UnWindDate != td.ExerciseDate)
|
|
{
|
|
throw new ServiceException($"只支持到期日互换,了结日期[{td.UnWindDate}]和到日期[{td.ExerciseDate}]不一致");
|
|
}
|
|
|
|
td.FinalPrice = reader.GetDouble("了结标的价格", false);
|
|
|
|
var eodpriceProvider = new YLErp.Modules.DataProviderModule.EodPriceProvider((DateTime)td.UnWindDate);
|
|
|
|
if (td.FinalPrice == null)
|
|
{
|
|
td.FinalPrice = eodpriceProvider.GetPrice(td.UnderlyingCode, SettlementTypeEnum.ClosePrice);//平仓当天标的价格;
|
|
}
|
|
|
|
var toEndAmount = reader.GetDouble("了结总额", false);
|
|
UnwindSwapTradeCashHandle(td, action, toEndAmount);
|
|
}
|
|
|
|
#endregion
|
|
|
|
//记录审核日志
|
|
DbContext.TradeAuditLog.Add(new TradeAuditLog
|
|
{
|
|
TradeId = td.id,
|
|
Changes = null,
|
|
DataType = "00",
|
|
OptId = UserId,
|
|
OptName = UserName,
|
|
OptDate = OptDate,
|
|
OptType = "导入交易",
|
|
AuditFlag = TradeAuditFlag.operation
|
|
});
|
|
DbContext.SaveChanges();
|
|
return td;
|
|
}
|
|
|
|
private void UnwindSwapTradeCashHandle(trade td, string action, double? toEndAmount)
|
|
{
|
|
var client = DataCacheProvider.GetClientDataSource().GetData(td.ClientId);
|
|
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
|
|
|
|
//增加现金交割交易记录
|
|
var tc = new trade_cash();
|
|
DbContext.trade_cash.Add(tc);
|
|
|
|
tc.OptId = UserId;
|
|
tc.OptName = UserName;
|
|
tc.OptDate = OptDate;
|
|
tc.ExceciseType = "现金";
|
|
tc.TradeType = td.BuySell;
|
|
tc.CallPut = td.CallPut;
|
|
tc.Notional = td.Notional;
|
|
tc.TradeAmount = td.TradeAmount;
|
|
tc.IsLastAction = true;
|
|
tc.TradeId = td.id;
|
|
tc.FinalPrice = td.FinalPrice;
|
|
tc.UnwindType = "全部平仓";
|
|
tc.UnwindNotional = td.Notional;
|
|
tc.UnwindTradeAmount = td.TradeAmount;
|
|
tc.UnwindPercentRate = 1;
|
|
tc.NotionalPercentRate = tc.UnwindPercentRate;
|
|
|
|
var Amount = toEndAmount ?? 0;
|
|
|
|
if (td.trade_swap.IsPayFloatingProfit)
|
|
{
|
|
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, td.UnWindDate.Value, seekPreday: true, currencyRateType: Amount < 0 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
|
|
|
|
td.TradeStatus = td.UnWindDate.Value == td.ExerciseDate ? "已到期" : "已平仓";
|
|
td.StockEqvNotional = 0;
|
|
td.Notional = 0;
|
|
td.TradeAmount = 0;
|
|
td.UnWindNotional = tc.UnwindNotional;
|
|
|
|
tc.Amount = Amount;
|
|
tc.QuoteAmount = Amount / currencyRate;
|
|
tc.CurrencyRate = currencyRate;
|
|
tc.Action = action == "平仓" ? ClientCashInCashOut.系统操作_平仓费 : ClientCashInCashOut.系统操作_互换;
|
|
tc.IsLastAction = true;
|
|
tc.Status = TradeCashStatusEnum.已执行;
|
|
tc.ValueDate = td.UnWindDate.Value;
|
|
tc.ValidState = "Valid";
|
|
tc.ExerciseWay = td.UnWindDate == td.ExerciseDate ? TradeCashExerciseWayEnum.到期行权 : TradeCashExerciseWayEnum.提前终止行权;
|
|
DbContext.SaveChanges();
|
|
|
|
|
|
//增加出入金记录
|
|
new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, tc, tc.ValueDate);
|
|
|
|
var trade_swap = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == tc.TradeId);
|
|
|
|
var trade_cash_swap = new trade_cash_swap();
|
|
trade_cash_swap.StartDate = td.StartDate.Value;
|
|
trade_cash_swap.PayStartPrice = trade_swap.PayFinalPrice ?? trade_swap.PaySpotPrice;
|
|
trade_cash_swap.PayFinalPrice = tc.FinalPrice;
|
|
trade_cash_swap.PayInitialAmount = -Amount;
|
|
trade_cash_swap.PayAmount = -Amount;
|
|
trade_cash_swap.PaySwapRate = PayoffSwapCalcService.GetSwapRateByDate(td.trade_swap.PaySwapTimeAndRate, td.UnWindDate.Value);
|
|
trade_cash_swap.GetExtraAmount = 0;
|
|
trade_cash_swap.GetCostFee = 0;
|
|
trade_cash_swap.GetAmount = 0;
|
|
trade_cash_swap.GetSwapRate = PayoffSwapCalcService.GetSwapRateByDate(td.trade_swap.GetSwapTimeAndRate, td.UnWindDate.Value);
|
|
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;
|
|
DbContext.trade_cash_swap.Add(trade_cash_swap);
|
|
|
|
var tcdGet = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = 0,
|
|
QuoteAmount = 0,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.利息.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdGet);
|
|
|
|
var tcdCostFeeGet = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = 0,
|
|
QuoteAmount = 0,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.了结手续费.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdCostFeeGet);
|
|
|
|
var tcdCostTradePriceGet = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = 0,
|
|
QuoteAmount = 0,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.开仓手续费.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdCostTradePriceGet);
|
|
|
|
var tcdPay = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = Amount,
|
|
QuoteAmount = Amount,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = false,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.浮动收益.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdPay);
|
|
}
|
|
else
|
|
{
|
|
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, td.UnWindDate.Value, seekPreday: true, currencyRateType: Amount < 0 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
|
|
|
|
tc.Amount = Amount;
|
|
tc.QuoteAmount = Amount / currencyRate;
|
|
tc.CurrencyRate = currencyRate;
|
|
tc.Action = action == "平仓" ? ClientCashInCashOut.系统操作_平仓费 : ClientCashInCashOut.系统操作_互换;
|
|
tc.IsLastAction = true;
|
|
tc.Status = TradeCashStatusEnum.已执行;
|
|
tc.ValueDate = td.UnWindDate.Value;
|
|
tc.ValidState = "Valid";
|
|
tc.ExerciseWay = td.UnWindDate == td.ExerciseDate ? TradeCashExerciseWayEnum.到期行权 : TradeCashExerciseWayEnum.提前终止行权;
|
|
DbContext.SaveChanges();
|
|
|
|
td.TradeStatus = tc.ValueDate == td.ExerciseDate ? "已到期" : "已平仓";
|
|
td.StockEqvNotional = 0;
|
|
td.Notional = 0;
|
|
td.TradeAmount = 0;
|
|
td.UnWindNotional = tc.UnwindNotional;
|
|
//增加出入金记录
|
|
new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, tc, tc.ValueDate);
|
|
|
|
var trade_swap = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == tc.TradeId);
|
|
var trade_cash_swap = new trade_cash_swap();
|
|
trade_cash_swap.StartDate = td.StartDate.Value;
|
|
trade_cash_swap.GetStartPrice = trade_swap.GetFinalPrice ?? trade_swap.GetSpotPrice;
|
|
trade_cash_swap.GetFinalPrice = tc.FinalPrice;
|
|
trade_cash_swap.GetInitialAmount = Amount;
|
|
trade_cash_swap.GetAmount = Amount;
|
|
trade_cash_swap.GetSwapRate = PayoffSwapCalcService.GetSwapRateByDate(td.trade_swap.GetSwapTimeAndRate, td.UnWindDate.Value);
|
|
trade_cash_swap.PayExtraAmount = 0;
|
|
trade_cash_swap.PayCostFee = 0;
|
|
trade_cash_swap.PayAmount = 0;
|
|
trade_cash_swap.PaySwapRate = PayoffSwapCalcService.GetSwapRateByDate(td.trade_swap.PaySwapTimeAndRate, td.UnWindDate.Value);
|
|
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;
|
|
DbContext.trade_cash_swap.Add(trade_cash_swap);
|
|
|
|
var tcdGet = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = 0,
|
|
QuoteAmount = 0,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.利息.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdGet);
|
|
|
|
var tcdCostFeeGet = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = 0,
|
|
QuoteAmount = 0,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.了结手续费.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdCostFeeGet);
|
|
|
|
var tcdCostTradePriceGet = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = 0,
|
|
QuoteAmount = 0,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.开仓手续费.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdCostTradePriceGet);
|
|
|
|
var tcdPay = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = Amount,
|
|
QuoteAmount = Amount,
|
|
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();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 导入了结历史数据交易
|
|
/// </summary>
|
|
/// <param name="streamIn"></param>
|
|
/// <param name="totalNum">当前文件中的目标期权总条数</param>
|
|
/// <param name="successNum">成功入库的数量</param>
|
|
public void ImportToEndSwapTradeHistroyDataFromExcel(Stream streamIn, out int totalNum, out int successNum)
|
|
{
|
|
totalNum = 0;
|
|
successNum = 0;
|
|
|
|
var rowIndex = 0;
|
|
try
|
|
{
|
|
var ds = Office.ExcelHelper.ReadExcelAsDataSet(streamIn, new[] { 0 }, 0);
|
|
|
|
if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 2)
|
|
{
|
|
throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" };
|
|
}
|
|
|
|
var table = ds.Tables[0];
|
|
var reader = new DataRowReader(table, 0);
|
|
|
|
rowIndex = 1;
|
|
totalNum = table.Rows.Count - rowIndex;
|
|
|
|
foreach (var row in table.Rows.Cast<DataRow>().Skip(1))
|
|
{
|
|
using (var trans = BeginTransaction())
|
|
{
|
|
rowIndex++;
|
|
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
|
|
{
|
|
totalNum--;
|
|
continue;
|
|
}
|
|
reader.SetDataRow(row);
|
|
|
|
HandleToEndSwapTradeHistroyData(reader);
|
|
|
|
successNum++;
|
|
|
|
trans.Commit();
|
|
}
|
|
}
|
|
}
|
|
catch (ServiceException se)
|
|
{
|
|
if (se.Tag != null)
|
|
{
|
|
throw;
|
|
}
|
|
|
|
throw new ServiceException($"已成功导入{successNum}条;\n第{rowIndex}行,{se.Message}");
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogFactory.GetLogger("导入收益互换了结").Error(ex);
|
|
throw new ServiceException($"已成功导入{successNum}条,\n第{rowIndex}行,发生错误:{ex.Message}", ex);
|
|
}
|
|
}
|
|
|
|
private trade HandleToEndSwapTradeHistroyData(DataRowReader reader)
|
|
{
|
|
var tradeNumnr = reader.GetString("交易编号", false);
|
|
var td = new trade();
|
|
var tdTable = DbContext.trade.FirstOrDefault(a => a.TradeNumber == tradeNumnr);
|
|
if (tdTable == null)
|
|
{
|
|
throw new ServiceException($"此交易编号[{td.TradeNumber}]不存在");
|
|
}
|
|
if (tdTable.TradeStatus != ConsTrade.确认成交)
|
|
{
|
|
throw new ServiceException("只有交易状态为‘确认成交’,才能进行批量了结导入");
|
|
}
|
|
|
|
td = tdTable;
|
|
td.trade_cash = new trade_cash();
|
|
td.trade_cash.UnwindPercentRate = reader.GetPercent("了结比例", false) ?? 0;
|
|
td.trade_cash.UnwindStockEqvNotional = reader.GetDouble("了结名义本金", false) ?? 0;
|
|
|
|
if (td.trade_cash.UnwindStockEqvNotional == 0 && td.trade_cash.UnwindPercentRate == 0)
|
|
{
|
|
throw new ServiceException($"交易编号[{td.TradeNumber}]中,了结名义本金与了结比例,必须填写一个值");
|
|
}
|
|
|
|
td.UnWindDate = reader.GetDate("了结日期", true);
|
|
|
|
var variety = DataCacheProvider.GetVariety(td.UnderlyingCode);
|
|
if (variety == null)
|
|
{
|
|
throw new ServiceException($"该标的[{td.UnderlyingCode}]对应的品种在系统中不存在");
|
|
}
|
|
else
|
|
{
|
|
var market = DataCacheProvider.GetMarketDataSource().AsQueryable().FirstOrDefault(x => x.MarketName == variety.TradingMarket);
|
|
if (QdpCalendarHelper.IsHoliday((DateTime)td.UnWindDate, string.IsNullOrWhiteSpace(market?.CalendarName) ? "chn" : market?.CalendarName))
|
|
{
|
|
throw new ServiceException("了结日期:" + td.UnWindDate + ",不能为节假日");
|
|
}
|
|
}
|
|
if (td.TradeDate > td.UnWindDate)
|
|
{
|
|
throw new ServiceException("了结日期必须要大于或等于成交日期");
|
|
}
|
|
if (td.UnWindDate > td.ExerciseDate)
|
|
{
|
|
throw new ServiceException("了结日期必须要小于或等于到期日期");
|
|
}
|
|
if (td.UnWindDate > valuedateBLL.ValueDate)
|
|
{
|
|
throw new ServiceException("了结日期必须要小于或等于系统日期");
|
|
}
|
|
|
|
td.FinalPrice = reader.GetDouble("了结标的价格", false);
|
|
|
|
var toEndAmount = reader.GetDouble("了结总额", false);
|
|
UnwindSwapTradeCashHandle(td, toEndAmount ?? 0);
|
|
|
|
return td;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 了结导入数据处理
|
|
/// </summary>
|
|
/// <param name="td"></param>
|
|
/// <param name="annualFee"></param>
|
|
/// <param name="costFee"></param>
|
|
private void UnwindSwapTradeCashHandle(trade td, double Amount)
|
|
{
|
|
var client = DataCacheProvider.GetClientDataSource().GetData(td.ClientId);
|
|
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
|
|
|
|
if (td.FinalPrice == null)
|
|
{
|
|
var eodpriceProvider = new YLErp.Modules.DataProviderModule.EodPriceProvider((DateTime)td.UnWindDate);
|
|
td.FinalPrice = eodpriceProvider.GetPrice(td.UnderlyingCode, SettlementTypeEnum.ClosePrice);//平仓当天标的价格;
|
|
}
|
|
|
|
td.trade_swap = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == td.id);
|
|
|
|
var unwindType = "部分平仓";
|
|
//获取平仓比例
|
|
if (td.trade_cash.UnwindPercentRate == 0 || (td.trade_cash.UnwindStockEqvNotional != 0 && td.trade_cash.UnwindPercentRate != 0))
|
|
{
|
|
if (td.StockEqvNotional <= td.trade_cash.UnwindStockEqvNotional + 1e-10)
|
|
{
|
|
td.trade_cash.UnwindStockEqvNotional = td.StockEqvNotional;
|
|
unwindType = "全部平仓";
|
|
}
|
|
td.trade_cash.UnwindPercentRate = td.trade_cash.UnwindStockEqvNotional / td.OriginalStockEqvNotional;
|
|
}
|
|
else if ((td.StockEqvNotional / td.OriginalStockEqvNotional) <= td.trade_cash.UnwindPercentRate + 1e-10)
|
|
{
|
|
td.trade_cash.UnwindPercentRate = td.StockEqvNotional / td.OriginalStockEqvNotional;
|
|
td.trade_cash.UnwindStockEqvNotional = td.StockEqvNotional;
|
|
unwindType = "全部平仓";
|
|
}
|
|
|
|
if (td.trade_cash.UnwindStockEqvNotional == 0)
|
|
{
|
|
if ((td.StockEqvNotional / td.OriginalStockEqvNotional) <= td.trade_cash.UnwindPercentRate + 1e-10)
|
|
{
|
|
td.trade_cash.UnwindPercentRate = td.StockEqvNotional / td.OriginalStockEqvNotional;
|
|
unwindType = "全部平仓";
|
|
}
|
|
td.trade_cash.UnwindStockEqvNotional = (double)(td.OriginalStockEqvNotional * td.trade_cash.UnwindPercentRate);
|
|
}
|
|
else if (td.StockEqvNotional <= td.trade_cash.UnwindStockEqvNotional + 1e-10)
|
|
{
|
|
td.trade_cash.UnwindStockEqvNotional = td.StockEqvNotional;
|
|
td.trade_cash.UnwindPercentRate = td.StockEqvNotional / td.OriginalStockEqvNotional;
|
|
unwindType = "全部平仓";
|
|
}
|
|
|
|
//增加现金交割交易记录
|
|
var tc = new trade_cash();
|
|
|
|
tc.OptId = UserId;
|
|
tc.OptName = UserName;
|
|
tc.OptDate = OptDate;
|
|
tc.ExceciseType = "现金";
|
|
tc.TradeType = td.BuySell;
|
|
tc.CallPut = td.CallPut;
|
|
tc.IsLastAction = true;
|
|
tc.TradeId = td.id;
|
|
tc.FinalPrice = td.FinalPrice;
|
|
tc.Notional = td.Notional;
|
|
tc.TradeAmount = td.TradeAmount;
|
|
tc.UnwindType = unwindType;
|
|
tc.UnwindNotional = td.trade_cash.UnwindPercentRate * td.OriginalNotional;
|
|
tc.UnwindTradeAmount = tc.UnwindNotional / um.CountRatio;
|
|
tc.UnwindPercentRate = td.trade_cash.UnwindPercentRate;
|
|
tc.NotionalPercentRate = tc.UnwindPercentRate;
|
|
|
|
if (td.trade_swap.IsPayFloatingProfit)
|
|
{
|
|
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, td.UnWindDate.Value, seekPreday: true, currencyRateType: Amount < 0 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
|
|
|
|
tc.CurrencyRate = currencyRate;
|
|
tc.Action = ClientCashInCashOut.系统操作_平仓费;
|
|
tc.IsLastAction = td.Notional <= 0 ? true : false;
|
|
tc.Status = TradeCashStatusEnum.已执行;
|
|
tc.ValueDate = td.UnWindDate.Value;
|
|
tc.ValidState = "Valid";
|
|
tc.ExerciseWay = TradeCashExerciseWayEnum.提前终止行权;
|
|
|
|
td.StockEqvNotional -= (double)(td.OriginalStockEqvNotional * tc.UnwindPercentRate);
|
|
td.Notional -= (double)(td.OriginalNotional * tc.UnwindPercentRate);
|
|
td.TradeAmount = td.Notional / um.CountRatio;
|
|
td.UnWindNotional = tc.UnwindNotional;
|
|
td.TradeStatus = tc.ValueDate == td.ExerciseDate ? "已到期" : (tc.UnwindType == "全部平仓" ? "已平仓" : td.TradeStatus);
|
|
td.HasPartialUnWind = tc.UnwindType == "部分平仓" ? 1 : 0;
|
|
|
|
DbContext.trade_cash.Add(tc);
|
|
DbContext.SaveChanges();
|
|
|
|
var trade_swap = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == tc.TradeId);
|
|
|
|
var trade_cash_swap = new trade_cash_swap();
|
|
trade_cash_swap.StartDate = td.StartDate.Value;
|
|
trade_cash_swap.PayStartPrice = trade_swap.PayFinalPrice ?? trade_swap.PaySpotPrice;
|
|
trade_cash_swap.PayFinalPrice = tc.FinalPrice;
|
|
trade_cash_swap.PayInitialAmount = -Amount;
|
|
trade_cash_swap.PayAmount = -Amount;
|
|
trade_cash_swap.PaySwapRate = PayoffSwapCalcService.GetSwapRateByDate(td.trade_swap.PaySwapTimeAndRate, td.UnWindDate.Value);
|
|
trade_cash_swap.GetExtraAmount = 0;
|
|
trade_cash_swap.GetCostFee = 0;
|
|
trade_cash_swap.GetAmount = 0;
|
|
trade_cash_swap.GetSwapRate = PayoffSwapCalcService.GetSwapRateByDate(td.trade_swap.GetSwapTimeAndRate, td.UnWindDate.Value);
|
|
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;
|
|
|
|
tc.Amount = (trade_cash_swap.GetAmount ?? 0) - (trade_cash_swap.PayAmount ?? 0);
|
|
tc.QuoteAmount = tc.Amount;
|
|
|
|
DbContext.trade_cash_swap.Add(trade_cash_swap);
|
|
DbContext.SaveChanges();
|
|
|
|
var tcdGet = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = 0,
|
|
QuoteAmount = 0,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.利息.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdGet);
|
|
|
|
var tcdCostFeeGet = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = 0,
|
|
QuoteAmount = 0,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.了结手续费.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdCostFeeGet);
|
|
|
|
var tcdCostTradePriceGet = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = 0,
|
|
QuoteAmount = 0,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.开仓手续费.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdCostTradePriceGet);
|
|
|
|
var tcdPay = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = Amount,
|
|
QuoteAmount = Amount,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = false,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.浮动收益.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdPay);
|
|
}
|
|
else
|
|
{
|
|
var currencyRate = new EodCurrencyRateService(UserInfo).GetCurrencyRate(td.QuoteCurrency, td.SettlementCurrency, td.UnWindDate.Value, seekPreday: true, currencyRateType: Amount < 0 ? CurrencyRateType.Buy : CurrencyRateType.Sell);
|
|
|
|
tc.CurrencyRate = currencyRate;
|
|
tc.Action = ClientCashInCashOut.系统操作_平仓费;
|
|
tc.IsLastAction = td.Notional <= 0 ? true : false;
|
|
tc.Status = TradeCashStatusEnum.已执行;
|
|
tc.ValueDate = td.UnWindDate.Value;
|
|
tc.ValidState = "Valid";
|
|
tc.ExerciseWay = TradeCashExerciseWayEnum.提前终止行权;
|
|
|
|
td.StockEqvNotional -= (double)(td.OriginalStockEqvNotional * tc.UnwindPercentRate);
|
|
td.Notional -= (double)(td.OriginalNotional * tc.UnwindPercentRate);
|
|
td.TradeAmount = td.Notional / um.CountRatio;
|
|
td.UnWindNotional = tc.UnwindNotional;
|
|
td.TradeStatus = tc.ValueDate == td.ExerciseDate ? "已到期" : (tc.UnwindType == "全部平仓" ? "已平仓" : td.TradeStatus);
|
|
td.HasPartialUnWind = tc.UnwindType == "部分平仓" ? 1 : 0;
|
|
|
|
DbContext.trade_cash.Add(tc);
|
|
DbContext.SaveChanges();
|
|
|
|
var trade_swap = DbContext.trade_swap.FirstOrDefault(x => x.TradeId == tc.TradeId);
|
|
var trade_cash_swap = new trade_cash_swap();
|
|
trade_cash_swap.StartDate = td.StartDate.Value;
|
|
trade_cash_swap.GetStartPrice = trade_swap.GetFinalPrice ?? trade_swap.GetSpotPrice;
|
|
trade_cash_swap.GetFinalPrice = tc.FinalPrice;
|
|
trade_cash_swap.GetInitialAmount = Amount;
|
|
trade_cash_swap.GetAmount = Amount;
|
|
trade_cash_swap.GetSwapRate = PayoffSwapCalcService.GetSwapRateByDate(td.trade_swap.GetSwapTimeAndRate, td.UnWindDate.Value);
|
|
trade_cash_swap.PayExtraAmount = 0;
|
|
trade_cash_swap.PayCostFee = 0;
|
|
trade_cash_swap.PayAmount = 0;
|
|
trade_cash_swap.PaySwapRate = PayoffSwapCalcService.GetSwapRateByDate(td.trade_swap.PaySwapTimeAndRate, td.UnWindDate.Value);
|
|
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;
|
|
|
|
tc.Amount = (trade_cash_swap.GetAmount ?? 0) - (trade_cash_swap.PayAmount ?? 0);
|
|
tc.QuoteAmount = tc.Amount;
|
|
DbContext.trade_cash_swap.Add(trade_cash_swap);
|
|
DbContext.SaveChanges();
|
|
|
|
var tcdGet = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = 0,
|
|
QuoteAmount = 0,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.利息.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdGet);
|
|
|
|
var tcdCostFeeGet = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = 0,
|
|
QuoteAmount = 0,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.了结手续费.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdCostFeeGet);
|
|
|
|
var tcdCostTradePriceGet = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = 0,
|
|
QuoteAmount = 0,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = true,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.开仓手续费.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdCostTradePriceGet);
|
|
|
|
var tcdPay = new trade_cash_detail
|
|
{
|
|
TradeId = tc.TradeId,
|
|
TradeCashId = tc.id,
|
|
Action = tc.Action,
|
|
Amount = Amount,
|
|
QuoteAmount = Amount,
|
|
ValueDate = tc.ValueDate,
|
|
IsForGet = false,
|
|
OptId = tc.OptId,
|
|
OptName = tc.OptName,
|
|
OptDate = DateTime.Now,
|
|
TradeCashType = TradeCashTypeEnum.浮动收益.ToString()
|
|
};
|
|
DbContext.trade_cash_detail.Add(tcdPay);
|
|
}
|
|
|
|
//增加出入金记录
|
|
new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, tc, tc.ValueDate);
|
|
|
|
var auditLog = new TradeAuditLog
|
|
{
|
|
TradeId = tc.TradeId,
|
|
Changes = null,
|
|
DataType = "00",
|
|
OptType = "批量了结-平仓",
|
|
OptId = UserId,
|
|
OptName = UserName,
|
|
OptDate = OptDate,
|
|
AuditFlag = TradeAuditFlag.operation
|
|
};
|
|
//记录审核日志
|
|
DbContext.TradeAuditLog.Add(auditLog);
|
|
DbContext.SaveChanges();
|
|
}
|
|
#endregion
|
|
|
|
#region 山西互换交易导入
|
|
private void ImportFromExcelSX(Stream streamIn, out int totalNum, out int successNum)
|
|
{
|
|
totalNum = 0;
|
|
successNum = 0;
|
|
|
|
var rowIndex = 0;
|
|
|
|
var ds = Office.ExcelHelper.ReadExcelAsDataSet(streamIn, new[] { 0 }, 0);
|
|
|
|
if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 2)
|
|
{
|
|
throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" };
|
|
}
|
|
|
|
var table = ds.Tables[0];
|
|
var reader = new DataRowReader(table, 0);
|
|
|
|
|
|
|
|
rowIndex = 1;
|
|
totalNum = table.Rows.Count - rowIndex;
|
|
|
|
foreach (var row in table.Rows.Cast<DataRow>().Skip(1))
|
|
{
|
|
rowIndex++;
|
|
|
|
reader.SetDataRow(row);
|
|
|
|
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
|
|
{
|
|
totalNum--;
|
|
continue;
|
|
}
|
|
|
|
var importSwap = MapSwap(reader, out var amount, out var getAmount, out var payAmount);
|
|
var saveChecker = new OtcOptionSaveChecker(this).CheckBasic(importSwap);
|
|
|
|
//簿记、交易员、交易对手
|
|
saveChecker.CheckAssetBook(importSwap).CheckTrader(importSwap);
|
|
if (importSwap != null)
|
|
{
|
|
var saveTrade = new TradeSaveService(OptUser).SaveTrade(importSwap, TradeSourceEnum.导入交易);
|
|
var trade = DbContext.trade.Find(importSwap.id);
|
|
trade.trade_swap = saveTrade.trade_swap;
|
|
trade.TradeOldStatus = trade.TradeStatus;
|
|
trade.TradeStatus = ConsTrade.确认成交;
|
|
new ClientCashInCashOutService(this).SaveClientCashInCashOut(trade);
|
|
|
|
if (trade.UnWindDate == trade.SettlementDate)
|
|
{
|
|
trade.TradeStatus = ConsTrade.已到期;
|
|
}
|
|
else
|
|
{
|
|
trade.TradeStatus = ConsTrade.已平仓;
|
|
}
|
|
|
|
var tc = new trade_cash();
|
|
DbContext.trade_cash.Add(tc);
|
|
|
|
tc.StartDate = trade.StartDate.Value;
|
|
tc.ValidState = "Valid";
|
|
tc.OptId = UserId;
|
|
tc.OptName = UserName;
|
|
tc.OptDate = OptDate;
|
|
tc.ExceciseType = "现金";
|
|
tc.TradeType = trade.BuySell;
|
|
tc.CallPut = trade.CallPut;
|
|
tc.Strike = trade.IsMoneynessOptionData ? (trade.Strike * trade.SpotPrice) : trade.Strike;
|
|
tc.Notional = trade.Notional;
|
|
tc.TradeAmount = trade.Amount;
|
|
tc.IsLastAction = true;
|
|
tc.Amount = amount;
|
|
|
|
//1.远期存入平仓时算出的预付金占用成本
|
|
//2.部分行权时候的额外金额
|
|
tc.ExtraAmount = 0;
|
|
tc.UnwindPrice = trade.FinalPrice;
|
|
tc.TradeId = trade.id;
|
|
tc.FinalPrice = trade.FinalPrice;
|
|
tc.SpotPrice = trade.TradePrice;
|
|
tc.HappenedDate = trade.UnWindDate;
|
|
tc.UnwindType = "全部平仓";
|
|
tc.UnwindPercentRate = 1;
|
|
|
|
tc.UnwindNotional = trade.Notional;
|
|
tc.UnwindTradeAmount = trade.TradeAmount;
|
|
|
|
tc.Action = ClientCashInCashOut.系统操作_平仓费;
|
|
tc.Status = DBModels.Enums.TradeCashStatusEnum.已执行;
|
|
tc.ValueDate = trade.UnWindDate.Value;
|
|
|
|
DbContext.SaveChanges();
|
|
|
|
var ee = new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(trade, tc, tc.ValueDate);
|
|
|
|
var swapTrade = trade.trade_swap;
|
|
var trade_cash_swap = new trade_cash_swap()
|
|
{
|
|
GetAmount = getAmount,
|
|
PayAmount = payAmount
|
|
};
|
|
trade_cash_swap.StartDate = tc.StartDate;
|
|
if (swapTrade.IsGetFloatingProfit)
|
|
{
|
|
trade_cash_swap.GetStartPrice = swapTrade.GetSpotPrice ?? 0;
|
|
trade_cash_swap.GetFinalPrice = swapTrade.GetFinalPrice ?? 0;
|
|
}
|
|
if (swapTrade.IsPayFloatingProfit)
|
|
{
|
|
trade_cash_swap.PayStartPrice = swapTrade.PaySpotPrice ?? 0;
|
|
trade_cash_swap.PayFinalPrice = swapTrade.PayFinalPrice ?? 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;
|
|
DbContext.trade_cash_swap.Add(trade_cash_swap);
|
|
//终止 trade_cash
|
|
|
|
DbContext.SaveChanges();
|
|
successNum++;
|
|
|
|
}
|
|
//结算 trade cash
|
|
}
|
|
}
|
|
|
|
private trade MapSwap(DataRowReader reader, out double winLoss, out double getAmount, out double payAmount)
|
|
{
|
|
var td = new trade();
|
|
|
|
//基本要素
|
|
td.TradeNumber = reader.GetString("交易确认书编号(双方约定)", false);
|
|
td.AssetBookName = reader.GetString("簿记账户", true);
|
|
td.TraderName = reader.GetString("交易员", true);
|
|
td.TradeType = "收益互换";
|
|
td.ClientName = reader.GetString("交易对手方", true);
|
|
|
|
if (string.IsNullOrWhiteSpace(td.ClientName))
|
|
{
|
|
throw new ServiceException("交易对手方名称 必须填写");
|
|
}
|
|
|
|
//交易日期
|
|
td.TradeDate = reader.GetDate("起始日", true);
|
|
td.ExerciseDate = reader.GetDate("到期日", true);
|
|
|
|
td.StartDate = td.TradeDate;
|
|
//结算日期
|
|
td.SettlementDate = td.ExerciseDate;
|
|
|
|
td.StockEqvNotional = reader.GetDouble("名义本金(人民币)", true) ?? 0;
|
|
td.MarginTemplateName = null;
|
|
td.UnWindDate = reader.GetDate("提前终止日/终止日", true);
|
|
td.Comments = reader.GetString("备注", false);
|
|
//td.UnderlyingName = reader.GetString("标的名称", true);
|
|
td.UnderlyingCode = reader.GetString("标的代码", true);
|
|
|
|
|
|
var clientQuery = DbContextFactory.GetClientDbContext(OptUser).client.AsQueryable();
|
|
if (!string.IsNullOrWhiteSpace(td.ClientName))
|
|
{
|
|
clientQuery = clientQuery.Where(c => c.Name == td.ClientName);
|
|
}
|
|
var client = clientQuery.Select(n => new { n.id, n.DerivativesInvestmentVarieties }).FirstOrDefault();
|
|
|
|
if (client == null)
|
|
{
|
|
throw new ServiceException($"交易对手方不存在,ClientName:{td.ClientName}");
|
|
}
|
|
else
|
|
{
|
|
if (!client.DerivativesInvestmentVarieties.Contains((int)DerivativesInvestmentVarietiesEnum.场外互换 + ""))
|
|
{
|
|
throw new ServiceException($"客户:{td.ClientName}未设置交易种类“场外互换”,无法生成互换交易!");
|
|
}
|
|
}
|
|
|
|
td.ClientId = client.id;
|
|
|
|
var um = DataCacheProvider.GetUnderlyingDataSource().AsQueryable().FirstOrDefault(o => o.UnderlyingCode == td.UnderlyingCode);
|
|
if (um == null)
|
|
{
|
|
throw new ServiceException($"{td.UnderlyingCode} 不存在,请先新建标的再导入");
|
|
}
|
|
else
|
|
{
|
|
td.UnderlyingId = um.id;
|
|
td.UnderlyingCode = um.UnderlyingCode;
|
|
td.UnderlyingName = um.UnderlyingName;
|
|
}
|
|
|
|
//币种
|
|
var underlyingModel = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
|
|
td.QuoteCurrency = DataCacheProvider.GetVarietyDataSource().GetData(underlyingModel.UnderlyingTypeId).QuoteCurrency;
|
|
|
|
var ExchangeRate = reader.GetDouble("汇率", false);
|
|
if (ExchangeRate != null)
|
|
{
|
|
if (td.QuoteCurrency != "CNY" && (!string.IsNullOrEmpty(td.QuoteCurrency)))
|
|
{
|
|
td.MetaDic.Add("ExchangeRate", ExchangeRate.ToString());
|
|
}
|
|
}
|
|
//td.MetaDic = new Dictionary<string, string>() {
|
|
// { "组合标的", "" },
|
|
// { "组合标的2", "" },
|
|
// { "交易场所", "" },
|
|
// { "清算机构", "" },
|
|
// { "主协议编号", "" },
|
|
// { "补充协议编号", "" }};
|
|
|
|
td.OpponentRole = "甲方";
|
|
|
|
|
|
|
|
double.TryParse(Regex.Match(reader.GetString("标的数量", false), @"^\d+((\,\d{3})+)?(\.\d+)?").Value, out var notional);
|
|
double.TryParse(Regex.Match(reader.GetString("标的初始价格", false), @"^\d+((\,\d{3})+)?(\.\d+)?").Value, out var spotPrice);
|
|
double.TryParse(Regex.Match(reader.GetString("标的提前终止日/终止日价格", false), @"^\d+((\,\d{3})+)?(\.\d+)?").Value, out var finalPrice);
|
|
|
|
td.Notional = notional;
|
|
td.TradeAmount = notional;
|
|
td.OriginalNotional = notional;
|
|
td.SpotPrice = spotPrice;
|
|
td.FinalPrice = finalPrice;
|
|
var swapTrade = new trade_swap();
|
|
swapTrade.RateCalcMode = GetRateCalcMode(reader.GetString("计息方式", true));
|
|
swapTrade.AnnualDays = reader.GetInt("年化天数", true);
|
|
swapTrade.AnnualVarIncome = reader.GetString("浮动收益年化", true) == "是";
|
|
swapTrade.GetSwapRate = reader.GetPercent("我方收取互换利率(年化)", false) ?? 0;
|
|
swapTrade.PaySwapRate = reader.GetPercent("我方支付互换利率(年化)", false) ?? 0;
|
|
if (swapTrade.GetSwapRate >= 0)
|
|
{
|
|
swapTrade.GetSwapTimeAndRate = td.ExerciseDate + ";" + swapTrade.GetSwapRate;
|
|
}
|
|
if (swapTrade.PaySwapRate >= 0)
|
|
{
|
|
swapTrade.PaySwapTimeAndRate = td.ExerciseDate + ";" + swapTrade.PaySwapRate;
|
|
}
|
|
|
|
swapTrade.GetLongShort = reader.GetString("我方收取浮动收益", false);
|
|
swapTrade.PayLongShort = reader.GetString("我方支付浮动收益", false);
|
|
if (!string.IsNullOrWhiteSpace(swapTrade.GetLongShort))
|
|
{
|
|
swapTrade.GetUnderlyingCode = td.UnderlyingCode;
|
|
swapTrade.GetUnderlyingId = td.UnderlyingId;
|
|
swapTrade.IsGetFloatingProfit = true;
|
|
swapTrade.GetNotional = notional;
|
|
swapTrade.GetTradeAmount = notional;
|
|
swapTrade.GetSpotPrice = spotPrice;
|
|
swapTrade.GetFinalPrice = finalPrice;
|
|
}
|
|
else
|
|
{
|
|
swapTrade.IsGetFloatingProfit = false;
|
|
}
|
|
|
|
if (!string.IsNullOrWhiteSpace(swapTrade.PayLongShort))
|
|
{
|
|
swapTrade.PayUnderlyingCode = td.UnderlyingCode;
|
|
swapTrade.PayUnderlyingId = td.UnderlyingId;
|
|
swapTrade.IsPayFloatingProfit = true;
|
|
swapTrade.PayNotional = notional;
|
|
swapTrade.PayTradeAmount = notional;
|
|
swapTrade.PaySpotPrice = spotPrice;
|
|
swapTrade.PayFinalPrice = finalPrice;
|
|
}
|
|
else
|
|
{
|
|
swapTrade.IsPayFloatingProfit = false;
|
|
}
|
|
|
|
|
|
winLoss = reader.GetDouble("我方损益", true) ?? 0;
|
|
getAmount = reader.GetDouble("我方收取现金流", false) ?? 0;
|
|
payAmount = reader.GetDouble("我方支付现金流", false) ?? 0;
|
|
|
|
//swapTrade. = winLoss >= 0 :
|
|
/*
|
|
data["UnderlyingId"] = data["trade_swap.PayUnderlyingId"];
|
|
data["UnderlyingCode"] = data["trade_swap.PayUnderlyingCode"];
|
|
*/
|
|
td.trade_swap = swapTrade;
|
|
return td;
|
|
}
|
|
|
|
#endregion
|
|
|
|
public void UploadClientVarietyConfig(Stream streamIn, out int totalNum, out int successNum)
|
|
{
|
|
totalNum = 0;
|
|
successNum = 0;
|
|
|
|
var rowIndex = 0;
|
|
|
|
var ds = Office.ExcelHelper.ReadExcelAsDataSet(streamIn, new[] { 0 }, 0);
|
|
|
|
if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 2)
|
|
{
|
|
throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" };
|
|
}
|
|
|
|
var table = ds.Tables[0];
|
|
var reader = new DataRowReader(table, 0);
|
|
|
|
rowIndex = 1;
|
|
totalNum = table.Rows.Count - rowIndex;
|
|
|
|
foreach (var row in table.Rows.Cast<DataRow>().Skip(1))
|
|
{
|
|
rowIndex++;
|
|
|
|
reader.SetDataRow(row);
|
|
|
|
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
|
|
{
|
|
totalNum--;
|
|
continue;
|
|
}
|
|
|
|
var config = MapClientVarietyConfig(reader);
|
|
if (config != null)
|
|
{
|
|
successNum++;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
private client_variety_config MapClientVarietyConfig(DataRowReader reader)
|
|
{
|
|
var clientNumber = reader.GetString("客户编号", true);
|
|
var varietyCode = reader.GetString("品种代码", true);
|
|
var client = ClientModule.ClientDataQueryService.GetClientByNumber(clientNumber);
|
|
if (client == null)
|
|
{
|
|
throw new ServiceException($"该客户[{clientNumber}]在系统中不存在");
|
|
}
|
|
var variety = DbContext.variety.Where(o => o.VarietyCode == varietyCode || o.VarietyName == varietyCode).FirstOrDefault();
|
|
if (variety == null)
|
|
{
|
|
throw new ServiceException($"该品种[{varietyCode}]在系统中不存在");
|
|
}
|
|
|
|
var config = new client_variety_config()
|
|
{
|
|
ValueDate = reader.GetDate("生效日期", true).Value,
|
|
ClientId = client.id,
|
|
VarietyId = variety.id,
|
|
SingleFee = reader.GetDouble("按手数收费", false) ?? 0,
|
|
UnAnnualRate = reader.GetPercent("按名义本金收费", false) ?? 0,
|
|
AnnualRate = reader.GetPercent("年化利率", false) ?? 0,
|
|
AnnualDays = reader.GetInt("年化天数", false) ?? 365,
|
|
Multiple = reader.GetDouble("倍数", false) ?? 0,
|
|
OptId = UserId,
|
|
OptName = UserName,
|
|
OptDate = DateTime.Now
|
|
};
|
|
|
|
if (DbContext.client_variety_config.Any(x => x.ClientId == config.ClientId && x.VarietyId == config.VarietyId && x.ValueDate == config.ValueDate))
|
|
{
|
|
throw new Exception($"同一客户[{clientNumber}]同一品种[{varietyCode}]不支持在同一天[{config.ValueDate.ToString("yyyy-MM-dd")}]有多条配置记录");
|
|
}
|
|
if (config.SingleFee > 0 && config.UnAnnualRate > 0)
|
|
{
|
|
throw new Exception($"按手数收费和按名义本金收费不能同时设置");
|
|
}
|
|
var types = new List<int>();
|
|
if (config.SingleFee != 0)
|
|
{
|
|
types.Add(1);
|
|
}
|
|
if (config.AnnualRate != 0)
|
|
{
|
|
types.Add(2);
|
|
}
|
|
if (config.UnAnnualRate != 0)
|
|
{
|
|
types.Add(3);
|
|
}
|
|
config.FeeType = string.Join(",", types);
|
|
DbContext.client_variety_config.Add(config);
|
|
DbContext.SaveChanges();
|
|
|
|
return config;
|
|
}
|
|
|
|
#region---内部业务类----
|
|
|
|
class DataRowTopTypeReader
|
|
{
|
|
DataRow _row;
|
|
|
|
readonly Dictionary<string, int> _colMap;
|
|
|
|
public DataRowTopTypeReader(DataTable table)
|
|
{
|
|
var colCount = table.Columns.Count;
|
|
|
|
_colMap = new Dictionary<string, int>(colCount, StringComparer.OrdinalIgnoreCase);
|
|
|
|
var row1 = table.Rows[0];
|
|
var row2 = table.Rows[1];
|
|
var preCol1 = string.Empty;
|
|
|
|
for (var index = 0; index < colCount; index++)
|
|
{
|
|
var col1 = row1[index]?.ToString()?.Trim();
|
|
var col2 = row2[index]?.ToString();
|
|
if (string.IsNullOrWhiteSpace(col2))
|
|
{
|
|
continue;
|
|
}
|
|
if (!string.IsNullOrWhiteSpace(col1))
|
|
{
|
|
preCol1 = col1;
|
|
}
|
|
col2 = col2.Replace("%", "").Trim();
|
|
_colMap[preCol1 + col2] = index;
|
|
}
|
|
}
|
|
|
|
public string TopType { get; private set; }
|
|
|
|
/// <summary>
|
|
/// 设置datarow
|
|
/// </summary>
|
|
public void SetDataRow(DataRow row)
|
|
{
|
|
_row = row;
|
|
TopType = "基本要素";
|
|
}
|
|
|
|
/// <summary>
|
|
/// 设置顶部类型
|
|
/// </summary>
|
|
public void SetTopType(string type)
|
|
{
|
|
TopType = type;
|
|
}
|
|
|
|
public string GetString(string fieldName, bool required = false)
|
|
{
|
|
var str = _colMap.TryGetValue(TopType + fieldName, out var colIndex) ? _row[colIndex]?.ToString()?.Trim() : null;
|
|
|
|
if (required && string.IsNullOrWhiteSpace(str))
|
|
{
|
|
throw new ServiceException($"[{TopType}]{fieldName} 必须填写");
|
|
}
|
|
|
|
return str;
|
|
}
|
|
|
|
public int? GetInt(string fieldName, bool required)
|
|
{
|
|
var str = GetString(fieldName, required);
|
|
|
|
if (!required && string.IsNullOrEmpty(str))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return int.TryParse(str, out var num) ? num : throw new ServiceException($"[{TopType}]{fieldName} 填写错误:{str}");
|
|
}
|
|
|
|
public double? GetDoubleOrPercent(string fieldName, bool required, bool percent)
|
|
{
|
|
var str = GetString(fieldName, required);
|
|
|
|
if (!required && string.IsNullOrWhiteSpace(str))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (percent && (percent = str.EndsWith("%")))
|
|
{
|
|
str = str.TrimEnd('%');
|
|
}
|
|
|
|
return double.TryParse(str, out var num) ? (percent ? num / 100 : num) : throw new ServiceException($"[{TopType}]{fieldName} 填写错误:{str}");
|
|
}
|
|
|
|
public double? GetDouble(string fieldName, bool required = false)
|
|
{
|
|
var str = GetString(fieldName, required);
|
|
|
|
if (!required && string.IsNullOrWhiteSpace(str))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return double.TryParse(str, out var num) ? num : throw new ServiceException($"[{TopType}]{fieldName} 填写错误:{str}");
|
|
}
|
|
|
|
//为了兼容模板修改导致的字段名称改变问题
|
|
public double? GetDouble(string fieldName, string fieldName2, bool required = false)
|
|
{
|
|
var str = GetString(fieldName, false) ?? GetString(fieldName2, false);
|
|
|
|
if (string.IsNullOrWhiteSpace(str))
|
|
{
|
|
return required ? throw new ServiceException($"[{TopType}]{fieldName} 必须填写") : (double?)null;
|
|
}
|
|
|
|
return double.TryParse(str, out var num) ? num : throw new ServiceException($"[{TopType}]{fieldName} 填写错误:{str}");
|
|
}
|
|
|
|
public double? GetPercent(string fieldName, bool required = false)
|
|
{
|
|
var str = GetString(fieldName, required);
|
|
|
|
if (!required && string.IsNullOrWhiteSpace(str))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var percent = str.EndsWith("%");
|
|
|
|
if (percent)
|
|
{
|
|
str = str.TrimEnd('%');
|
|
}
|
|
|
|
return double.TryParse(str, out var num) ? (percent ? num / 100 : num) : throw new ServiceException($"[{TopType}]{fieldName} 填写错误:{str}");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 获取日期(不包括时间)
|
|
/// </summary>
|
|
public DateTime? GetDate(string fieldName, bool required = false)
|
|
{
|
|
var str = GetString(fieldName, required);
|
|
|
|
if (!required && string.IsNullOrWhiteSpace(str))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
if (str.Length == 8 && Regex.IsMatch(str, @"^\d+$"))
|
|
{
|
|
return DateTime.TryParseExact(str, "yyyyMMdd", CultureInfo.InvariantCulture, DateTimeStyles.None, out var dt2) ? dt2 : throw new ServiceException($"{fieldName} 填写错误:{str}");
|
|
}
|
|
|
|
return DateTime.TryParse(str, out var dt) ? dt.Date : throw new ServiceException($"[{TopType}]{fieldName} 填写错误:{str}");
|
|
}
|
|
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public int? GetInt32(string fieldName, bool required = false)
|
|
{
|
|
var str = GetString(fieldName, required);
|
|
|
|
if (!required && string.IsNullOrWhiteSpace(str))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
return int.TryParse(str, out var num) ? num : throw new ServiceException($"[{TopType}]{fieldName} 填写错误:{str}");
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|