Files
zszq-trs/YLErpDAL/Modules/TradeModule/OrderModule/OtcTradeImportService.cs
T
2024-05-09 14:06:26 +08:00

2585 lines
103 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BaseOUDAL;
using Qdp.Pricing.Base.Enums;
using Qdp.Pricing.Base.Implementations;
using System.Data;
using System.Globalization;
using System.Text.RegularExpressions;
using YLErp.Commons;
using YLErp.DBModels.Consts;
using YLErp.DBModels.Enums;
using YLErp.DBModels.Helpers;
using YLErp.Enums;
using YLErp.Helpers;
using YLErp.Model.Enum;
using YLErp.Models;
using YLErp.Modules.DictionaryModule;
using YLErp.Modules.SalesModule;
using YLErp.Modules.StructureModule;
using YLErp.Modules.TradeModule.DealModule;
using YLErp.QdpModule;
namespace YLErp.Modules.TradeModule.OrderModule
{
/// <summary>
/// 场外交易导入服务
/// </summary>
public class OtcTradeImportService : YLBaseService
{
public OtcTradeImportService(YLBaseService baseService) : base(baseService)
{
}
public OtcTradeImportService(OptUserInfo userInfo) : base(userInfo)
{
}
/// <summary>
/// 从excel文件中导入场外期权交易
/// </summary>
public void ImportOptionTradesFromExcel(Stream streamIn, out int totalNum, out int successNum)
{
new OtcOptionTradeImportService(this).ImportFromExcel(streamIn, out totalNum, out successNum);
}
/// <summary>
/// 从excel文件中读取场外期权交易导入
/// </summary>
public List<OtcOptionTradeFullEx> ReadOptionTradesFromExcel(Stream streamIn)
{
return new OtcOptionTradeImportService(this).ReadFromExcel(streamIn);
}
}
/// <summary>
/// 场外期权交易导入服务
/// </summary>
class OtcOptionTradeImportService : OtcTradeSaveService
{
public OtcOptionTradeImportService(OptUserInfo userInfo) : base(userInfo)
{
}
public OtcOptionTradeImportService(YLBaseService baseService) : base(baseService)
{
}
private readonly ErpBaseContext basedb = new ErpBaseContext();
/// <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(stream: streamIn, includeSheetIndexs: new[] { 0 }, headerRowIndex: 0);
if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 3)
{
throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" };
}
if (ds.Tables[0].TableName != "交易导入模板V3")
{
throw new ServiceException("请使用最新交易导入模板V3") { Tag = "111" };
}
var table = ds.Tables[0];
var reader = new DataRowReader(table);
rowIndex = 2;
totalNum = table.Rows.Count - rowIndex;
foreach (var row in table.Rows.Cast<DataRow>().Skip(2))
{
rowIndex++;
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
{
totalNum--;
continue;
}
reader.SetDataRow(row);
//映射导入数据到交易对象
var importTrade = MapTrade(reader);
if (groupTradeList.Count > 0 && importTrade.IsGroup != 2)
{
rowIndex -= 1;
//save 方法里会清空列表
successNum += InnerSaveGroupTrade(groupTradeList);
rowIndex += 1;
}
//保存结构化交易
if (structureTradeList.Count > 0 &&
(structureTradeList[0].StructureType != importTrade.StructureType || structureTradeList[0].CalcId != importTrade.CalcId))
{
rowIndex -= 1;
successNum += InnerSaveStructureTrade(structureTradeList);
rowIndex += 1;
}
//当上一个组合保存完毕,接下来又遇到组合主交易时
if (importTrade.IsGroup == 1 || importTrade.IsGroup == 2)
{
groupTradeList.Add(importTrade);
}
//当上一个组合保存完毕,接下来遇到非组合主交易时
else
{
//结构化交易
if (!string.IsNullOrWhiteSpace(importTrade.StructureType) && importTrade.TradeType != "自定义交易")
{
structureTradeList.Add(importTrade);
}
//单笔交易
else
{
InnerSaveTrade(importTrade);
successNum++;
}
}
}
}
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);
}
try
{
//保存组合交易
if (groupTradeList.Count > 0)
{
rowIndex -= (groupTradeList.Count - 1);
successNum += InnerSaveGroupTrade(groupTradeList);
}
//保存结构化
if (structureTradeList.Count > 0)
{
rowIndex -= (structureTradeList.Count - 1);
successNum += InnerSaveStructureTrade(structureTradeList);
}
}
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>
public List<OtcOptionTradeFullEx> ReadFromExcel(Stream streamIn)
{
var rowIndex = 0;
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" };
}
rowIndex = 2;
var table = ds.Tables[0];
var reader = new DataRowReader(table);
var list = new List<OtcOptionTradeFullEx>(table.Rows.Count);
foreach (var row in table.Rows.Cast<DataRow>().Skip(2))
{
rowIndex++;
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
{
continue;
}
reader.SetDataRow(row);
//映射导入数据到交易对象
var importTrade = MapTrade(reader);
list.Add(importTrade);
}
return list;
}
//保存交易
private void InnerSaveTrade(OtcOptionTradeFullEx importTrade)
{
using (var trans = DbContext.Database.BeginTransaction())
{
var dbTrade = SaveOptionTradeFromApiOrImport(importTrade, TradeSourceEnum.导入交易, trans);
if (importTrade.CloseRequest != null)
{
ExecuteClose(dbTrade, importTrade.CloseRequest);
}
trans.Commit();
}
}
//保存结构化交易
private int InnerSaveStructureTrade(List<OtcOptionTradeFullEx> structureTradeList)
{
var count = structureTradeList.Count;
if (count < 2)
{
throw new ServiceException("结构化交易组合必须有两条腿及以上");
}
if (structureTradeList.Select(n => n.TradeNumber).Distinct().Count() > 1)
{
throw new ServiceException("结构化交易组合必须有相同的交易编号");
}
//在底层服务已经做了验证:结构化交易组合必须有相同的交易对手方
using (var trans = DbContext.Database.BeginTransaction())
{
var dbTrade = SaveStructureOptionTradeFromApiOrImport(new StructureOrderRequest
{
Trades = structureTradeList,
StructureType = structureTradeList[0].StructureType
}, TradeSourceEnum.导入交易, trans);
var subTrades = dbTrade.SubTrades.ToArray();
DbContext.trade.Attach(dbTrade);
for (var i = 0; i < count; i++)
{
DbContext.trade.Attach(subTrades[i]);
ExecuteClose(subTrades[i], structureTradeList[i].CloseRequest);
}
structureTradeList.Clear();
trans.Commit();
}
return count;
}
private int InnerSaveGroupTrade(List<OtcOptionTradeFullEx> structureTradeList)
{
var count = structureTradeList.Count;
if (count <= 2)
{
throw new ServiceException("组合交易必须有两条子交易及以上");
}
//在底层服务已经做了验证:结构化交易组合必须有相同的交易对手方
using (var trans = DbContext.Database.BeginTransaction())
{
var dbTrade = SaveGroupOptionTradeFromApiOrImport(new StructureOrderRequest
{
Trades = structureTradeList
}, TradeSourceEnum.导入交易, trans);
structureTradeList.Clear();
trans.Commit();
}
return count;
}
private OtcOptionTradeFullEx MapTrade(DataRowReader reader)
{
var td = new OtcOptionTradeFullEx
{
//基本要素
TradeNumber = reader.GetString("交易编号"),
AssetBookName = reader.GetString("簿记账户名称", true),
TraderName = reader.GetString("交易员名称", true),
TradeType = reader.GetString("结构类型", true),
IsGroup = reader.GetString("组合交易类型") == "组合主交易" ? 1 : (reader.GetString("组合交易类型") == "组合子交易" ? 2 : 0),
ClientNumber = reader.GetString("交易对手方编号"),
ClientName = reader.GetString("交易对手方名称")
};
if (string.IsNullOrWhiteSpace(td.ClientNumber) && string.IsNullOrWhiteSpace(td.ClientName))
{
throw new ServiceException("交易对手方编号 或 交易对手方名称 必须填写其中一个");
}
var tradeTypes = new StructureService(OptUser).QueryStructureInfo(td.IsGroup == 1 ? StructureRangeEnum.BALCK_TRADE : StructureRangeEnum.CUSTOM_TRADE).Select(O => O.StructureName);
if (!ConsTrade.AllTradeTypes.Contains(td.TradeType) && td.TradeType != "累计期权三段式")
{
if (!tradeTypes.Contains(td.TradeType))
{
throw new ServiceException($"交易类型{td.TradeType}不合法");
}
if (td.IsGroup == 0)
{
td.StructureType = td.TradeType;
td.TradeType = "自定义交易";
}
}
var required = td.TradeType != "自定义交易" && td.TradeType != "现金流交易" && td.IsGroup != 1;
//交易方向
td.BuySell = reader.GetString("交易方向", true);
switch (td.BuySell)
{
case "Buy":
td.BuySell = "买入";
break;
case "Sell":
td.BuySell = "卖出";
break;
case "买入":
case "卖出":
break;
default:
throw new ServiceException("交易方向 填写错误:" + td.BuySell);
}
//看涨看跌
td.OptionType = reader.GetString("看涨看跌", required);
if (td.TradeType == "Risky期权" && td.OptionType != "看涨" && td.OptionType != "Call")
{
throw new ServiceException("Risky期权看涨看跌 必须为看涨");
}
switch (td.OptionType)
{
case "看涨":
case "看跌":
break;
case "Call":
td.OptionType = "看涨";
break;
case "Put":
td.OptionType = "看跌";
break;
default:
if (!string.IsNullOrWhiteSpace(td.OptionType))
{
throw new ServiceException("看涨看跌 填写错误:" + td.OptionType);
}
if (required)
{
throw new ServiceException("看涨看跌 必须填写");
}
break;
}
//行权方式(需要转换预校验会用到)
td.ExerciseMode = reader.GetString("行权方式", required);
switch (td.ExerciseMode)
{
case "欧式":
td.ExerciseMode = "European";
break;
case "美式":
td.ExerciseMode = "American";
break;
case "European":
case "American":
break;
default:
if (!string.IsNullOrWhiteSpace(td.ExerciseMode))
{
throw new ServiceException("行权方式 填写错误:" + td.ExerciseMode);
}
if (required)
{
throw new ServiceException("行权方式 必须填写");
}
break;
}
//交易日期
td.TradeDate = reader.GetDate("交易日期", true);
//标的代码
td.UnderlyingCode = reader.GetString("标的代码", td.TradeType != "现金流交易");
td.ExerciseDate = reader.GetDate("到期日期", true);
//结算日期
td.SettlementDate = reader.GetDate("结算日期");
if (PS.Config.Is浙期)
{
var flag = false;
var codes = new List<string>();
codes.Add(td.UnderlyingCode);
//判断标的是否为现货
flag = UndelyingHelper.IsCodesExistsCommoditySpot(codes, (um) =>
{
return um.UnderlyingInstrumentType == "CommoditySpot" ? true : false;
});
if (flag)
{
var dateStr = reader.GetDate("实际到期日期", false) ?? td.ExerciseDate;
td.MetaDic["ActualExerciseDate"] = dateStr.Value.ToString("yyyy-MM-dd");
}
}
//判断是否组合标的
var synthetic = DataCacheProvider.GetUnderlyingDataSource().GetSyntheticUnderlying(td.UnderlyingCode);
//标的价格(组合标的时忽略并由组合标的数据算出)
if (synthetic == null)
{
td.SpotPrice = reader.GetDouble("标的价格", td.TradeType != "现金流交易");
}
//相对行权价
td.IsMoneynessOption = reader.GetString("相对行权价");
//执行价格(亚式浮动行权价类型时非必填)
td.Strike = reader.GetDoubleOrPercent("执行价格", false, td.IsMoneynessOption == "是");
double? dtemp;
//权利金单价
td.TradeSinglePrice = dtemp = reader.GetDouble("权利金单价");
if (dtemp.HasValue)
{
td.HasFlag |= OtcOptionTradeFullHasFlag.TradeSinglePrice;
}
else
{
//权利金总额
td.TradePrice = dtemp = reader.GetDouble("权利金总额");
if (dtemp.HasValue)
{
td.HasFlag |= OtcOptionTradeFullHasFlag.TradePrice;
}
else
{
//期权费率
td.PremiumRate = dtemp = reader.GetPercent("期权费率");
if (dtemp.HasValue)
{
td.HasFlag |= OtcOptionTradeFullHasFlag.PremiumRate;
}
}
}
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
if (underlying == null)
{
throw new ServiceException($"标的{td.UnderlyingCode}信息不存在");
}
var variety = DataCacheProvider.GetVarietyDataSource().GetData(underlying.UnderlyingTypeId);
//币种
td.QuoteCurrency = variety?.QuoteCurrency;
//汇率
var ExchangeRate = reader.GetDouble("汇率", false);
if (ExchangeRate != null)
{
if (!string.IsNullOrEmpty(td.QuoteCurrency))
{
td.MetaDic.Add("ExchangeRate", ExchangeRate.ToString());
}
}
//参与率(百分比格式)
td.ParticipationRate = reader.GetPercent("参与率", td.TradeType == "Risky期权") ?? 1;
if(td.ParticipationRate.HasValue && td.ParticipationRate.Value < 0)
{
throw new ServiceException("[基本要素]参与率 不能小于0,当前填写值:" + td.ParticipationRate);
}
//有效交易份额
td.Notional = reader.GetDouble("有效交易份额") ?? 0;
//交易份额(虚拟)
var notionalV = reader.GetDouble("交易份额");
if (notionalV.HasValue && notionalV.Value > 0)
{
var ttypes = new[] { "凤凰期权", "雪球期权" };
td.Notional = notionalV.Value * (ttypes.Contains(td.TradeType) ? 1 : td.AnnualizeFactor ?? 1) * (td.ParticipationRate ?? 1);
}
if (td.TradeType != "累计期权" && td.TradeType != "累计期权三段式")
{
//名义本金
td.StockEqvNotional = reader.GetDouble("名义本金") ?? 0;
//有效名义本金
td.StockEqvNotionalReal = reader.GetDouble("有效名义本金") ?? reader.GetDouble("实际名义本金") ?? 0;
}
//期权年化
td.IsAnnualized = reader.GetString("期权年化") == "是";
if (td.IsAnnualized)
{
var annualizeFactor = reader.GetString("年化系数");
if (!string.IsNullOrEmpty(annualizeFactor))
{
var index = annualizeFactor.IndexOf('/');
if (index < 0)
{
throw new ServiceException("[基本要素]年化系数 不是正确格式(正确格式样例:25/244),当前填写值:" + annualizeFactor);
}
if (!int.TryParse(annualizeFactor.Substring(0, index).TrimEnd(), out var ttmDays) || ttmDays < 0)
{
throw new ServiceException("[基本要素]年化系数 '/'左边不是正确的天数:" + annualizeFactor);
}
if (!int.TryParse(annualizeFactor.Substring(index + 1).TrimStart(), out var daysOfYear) || daysOfYear < 1)
{
throw new ServiceException("[基本要素]年化系数 '/'右边不是正确的年天数:" + annualizeFactor);
}
td.AnnualizeFactor = (double)ttmDays / daysOfYear;
td.MetaDic[nameof(td.AnnualizeFactor)] = annualizeFactor;
}
}
bool IsUsePremiumRate = false;
if (td.HasFlag == OtcOptionTradeFullHasFlag.PremiumRate)
{
IsUsePremiumRate = true;
}
else if (td.HasFlag == OtcOptionTradeFullHasFlag.TradePrice)
{
IsUsePremiumRate = !(td.Notional > 0);
}
//保底收益
td.OriginalPrincipalSum = reader.GetDouble("保底收益总额") ?? 0;
double stockEqvNotional = td.StockEqvNotional > 0 ? td.StockEqvNotional : td.StockEqvNotionalReal;
if (IsUsePremiumRate)
{
td.PrincipalRateWrite = reader.GetPercent("保底收益") ?? 0;
td.SinglePrincipalWrite = TradeHelper.GetSinglePrincipal(stockEqvNotional, td.PrincipalRateWrite, td.Notional, td.AnnualizeFactor);
if (reader.GetDouble("保底收益总额") == null && reader.GetPercent("保底收益") != null)
{
td.OriginalPrincipalSum = TradeHelper.GetRateToPrincipalSum(stockEqvNotional, td.PrincipalRateWrite, td.AnnualizeFactor);
}
}
else
{
td.SinglePrincipalWrite = reader.GetDouble("保底收益") ?? 0;
td.PrincipalRateWrite = TradeHelper.GetPrincipalRate(stockEqvNotional, td.SinglePrincipalWrite, td.Notional, td.AnnualizeFactor);
if (reader.GetDouble("保底收益总额") == null && reader.GetPercent("保底收益") != null)
{
td.OriginalPrincipalSum = TradeHelper.GetSingleToPrincipalSum(td.Notional, td.SinglePrincipalWrite);
}
}
//无风险利率(百分比格式)
td.NoRiskRate = reader.GetPercent("无风险利率");
//分红率(百分比格式)
td.DividendRate = reader.GetPercent("分红率");
//销售员 提成方式 提成金额
var salesmen = reader.GetString("销售员");
if (PS.Config.ErpElement.SaleMode == YLErp.Configuration.Enums.SaleMode.CustomerManager)
{
//客户经理 提成方式 提成金额
salesmen = reader.GetString("客户经理");
}
if (!string.IsNullOrWhiteSpace(salesmen))
{
var salesCommission = new TradeSalesCommissionInfo
{
CommissionFixed = reader.GetString("提成方式") == "绝对值"
};
var commission = reader.GetPercent("提成金额", false);
if (commission < 0)
{
throw new ServiceException("销售佣金金额 不能小于0");
}
//todo 多人
salesCommission.SalesIds = GetSalesIds(salesmen);
salesCommission.Commission = commission;
salesCommission.ClientId = GetClientId(td.ClientName);
salesCommission.SaleMode = (int)PS.Config.ErpElement.SaleMode;
td.SalesCommission = salesCommission;
}
//备注
td.Comments = reader.GetString("备注");
//成交波动率(必需&百分比格式)
td.TradeOpenVolatility = reader.GetPercent("成交波动率", required);
//目标波动率(必需&百分比格式)
td.TradeCloseVolatility = reader.GetPercent("目标波动率", required);
//平滑过渡天数
td.NumOfSmoothingDays = reader.GetInt32("平滑过渡天数");
//存续天数
td.DurationDays = (short?)reader.GetInt32("存续天数");
//期末费率
td.MetaDic["期末费率"] = reader.GetString("期末费率");
//初始预付金
td.InitialMargin = reader.GetDouble("初始预付金");
//计算标识
td.CalcFlag = reader.GetInt32("计算标识") ?? 0;
//收益结算
var SettlementTypeStr = reader.GetString("收益结算");
switch (SettlementTypeStr)
{
case "收盘价":
td.SettlementType = SettlementTypeEnum.ClosePrice;
break;
case "结算价":
td.SettlementType = SettlementTypeEnum.SettlePrice;
break;
case "参考价":
td.SettlementType = SettlementTypeEnum.ReferencePrice;
break;
default:
if (!string.IsNullOrWhiteSpace(SettlementTypeStr))
{
throw new ServiceException("收益结算 填写错误:" + SettlementTypeStr);
}
break;
}
//结构说明
td.StructureIntroduction = reader.GetString("结构说明");
//自定义保存
if (td.TradeType == "自定义交易" || (td.IsGroup == 1 && td.TradeType != "气囊结构"))
{
reader.SetTopType("自定义属性");
ReadCustomizedOption(reader, td);
}
else
{
if (reader.CustomField.Length > 0)
{
reader.SetTopType("自定义属性");
var propertys = new List<ExtendInfoModel>();
foreach (var item in reader.CustomField)
{
var cusofield = reader.GetString(item);
if (!string.IsNullOrWhiteSpace(cusofield))
{
propertys.Add(new ExtendInfoModel()
{
name = item,
value = cusofield
});
}
}
td.MetaDic[ConsTradeMetaKey.tradeExtendInfo] = "自定义";
td.ExtendInfo = JsonHelper.Serialize(propertys);
}
reader.SetTopType(td.TradeType);
switch (td.TradeType)
{
case "香草期权":
case "合成价差期权":
break;
case "亚式期权":
ReadAsiaOption(reader, td);
break;
case "障碍期权":
ReadBarrierOption(reader, td);
break;
case "双鲨期权":
ReadDoubleSharkOption(reader, td);
break;
case "二元期权":
ReadBinaryOption(reader, td);
break;
case "区间累积期权":
ReadRangeAccOption(reader, td);
break;
case "气囊结构":
ReadAirBagOption(reader, td);
break;
case "收益增强结构":
//年化增强收益(必需&百分比格式)
td.AnnualizedEnhanceRate = reader.GetPercent("年化增强收益", true).Value;
break;
case "凤凰期权":
ReadAutoCallOption(reader, td);
break;
case "雪球期权":
ReadSnowBallOption(reader, td);
break;
case "累计期权":
ReadAccumulatorOption(reader, td);
break;
case "累计期权三段式":
ReadAccumulatorOptionSegmented(reader, td);
break;
case "现金流交易":
ReadCashFlow(reader, td);
break;
case "Risky期权":
ReadRisky(reader, td);
break;
default:
throw new ServiceException("交易类型 填写错误,不支持:" + td.TradeType);
}
}
if (!td.Strike.HasValue && TradeHelper.IsStrikeRequired(td))
{
throw new ServiceException("[基本要素]执行价格 必须填写");
}
//了结信息
td.CloseRequest = ReadCloseData(reader, td);
if (td.CloseRequest != null && td.SalesCommission != null)
{
td.SalesCommission.IsValid = true;
}
if (td.TradeType != "自定义交易")
{
//结构化交易
reader.SetTopType("结构化交易");
td.StructureType = reader.GetString("结构化类型");
if (!string.IsNullOrWhiteSpace(td.StructureType))
{
td.CalcId = reader.GetString("组合标识");
td.MetaDic["合约编号"] = reader.GetString("合约编号");
if (string.IsNullOrEmpty(td.CalcId))
{
td.CalcId = td.TradeNumber.TrimToNull() ?? td.MetaDic["合约编号"];
}
if (string.IsNullOrEmpty(td.CalcId))
{
throw new ServiceException($"[结构化交易]组合标识 必须填写");
}
}
}
//读取组合标的
if (synthetic != null)
{
reader.SetTopType("组合标的");
var sulist = new List<UnderlyingPriceModel>(4);
var codeSet = synthetic.GetUnderlyingCodes().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}");
}
sulist.Add(new UnderlyingPriceModel { UnderlyingCode = code, Price = reader.GetDouble("标的" + i + "_价格", true).Value });
}
if (codeSet.Any())
{
throw new ServiceException("[组合标的]未填写完整");
}
td.SyntheticPrices = sulist;
}
return td;
}
#region---读取奇异期权字段----
//亚式期权
private void ReadAsiaOption(DataRowReader reader, OtcOptionTradeFull td)
{
//均价起算日
td.AveragingPeriodStartDate = reader.GetDate("均价起算日");
//均价计算
td.PayoffType = reader.GetString("均价计算");
switch (td.PayoffType)
{
case "算术平均":
td.PayoffType = "ArithmeticAverage";
break;
case "几何平均":
td.PayoffType = "GeometricAverage";
break;
case "算术平均(离散)":
case "算术平均(离散)":
td.PayoffType = "DiscreteArithmeticAverage";
break;
case "增强算术平均":
td.PayoffType = "EnhancedArithmeticAverage";
break;
case "ArithmeticAverage":
case "GeometricAverage":
case "DiscreteArithmeticAverage":
case "EnhancedArithmeticAverage":
default:
td.PayoffType = string.IsNullOrWhiteSpace(td.PayoffType)
? "ArithmeticAverage"
: throw new ServiceException("[亚式期权]均价计算 填写错误,不支持:" + td.PayoffType);
break;
}
if (td.PayoffType == "EnhancedArithmeticAverage")
{
td.SettleMode = reader.GetString("结算类型");
switch (td.SettleMode)
{
case "递延":
case "AtEnd":
td.SettleMode = "AtEnd";
break;
case "立即":
case "AtHit":
default:
td.SettleMode = "AtHit";
break;
}
}
//行权价类型
td.StrikeType = reader.GetString("行权价类型");
switch (td.StrikeType)
{
case "固定行权价":
td.StrikeType = "Fixed";
break;
case "浮动行权价":
td.StrikeType = "Floating";
td.Strike = null;
break;
case "分段式":
td.StrikeType = "Segmented";
break;
case "Fixed":
case "Segmented":
break;
case "Floating":
td.Strike = null;
break;
default:
td.StrikeType = string.IsNullOrWhiteSpace(td.StrikeType)
? "Fixed" : throw new ServiceException("[亚式期权]行权价类型 填写错误,不支持:" + td.StrikeType);
break;
}
bool enhancedPriceRequired = td.PayoffType == "EnhancedArithmeticAverage" && td.StrikeType != "Floating";
td.EnhancedPrice = reader.GetDoubleOrPercent("增强价格", enhancedPriceRequired, td.IsMoneynessOptionData) ?? 0;
//杠杆率(百分比格式)
td.StrikeGearingFactor = reader.GetPercent("杠杆率");
}
//障碍期权
private void ReadBarrierOption(DataRowReader reader, OtcOptionTradeFull td)
{
var ismoneyness = td.IsMoneynessOption == "是";
//障碍类型
td.BarrierType = reader.GetString("障碍类型", true);
//障碍价格
td.BarrierLow = reader.GetDoubleOrPercent("障碍价格", true, ismoneyness).Value;
//高障碍价格
td.BarrierHigh = reader.GetDoubleOrPercent("高障碍价格", false, ismoneyness) ?? 0;
//补偿金额
td.Rebate = td.RebateRate = reader.GetDoubleOrPercent("补偿金额", false, td.IsUsePremiumRate == true);
//高障碍补偿金额
td.RebateHigh = td.RebateHighRate = reader.GetDoubleOrPercent("高障碍补偿金额", false, td.IsUsePremiumRate == true);
//障碍偏移
td.BarrierShift = reader.GetDouble("障碍偏移");
//观察方式
td.MonitorType = reader.GetString("观察方式");
//补偿按敲出日年化
td.RebateAnnualizedAtKO = reader.GetString("补偿按敲出日年化") == "是";
//补偿计息规则
td.RebateDayCount = reader.GetString("补偿计息规则") ?? "";
//补偿支付
ReadRebateType(reader, td);
//观察频率
ReadObservationDates(reader, td);
}
//双鲨期权
private void ReadDoubleSharkOption(DataRowReader reader, OtcOptionTradeFull td)
{
var ismoneyness = td.IsMoneynessOption == "是";
var isPremiumRate = td.IsUsePremiumRate == true;
//障碍价格
td.BarrierLow = reader.GetDoubleOrPercent("低障碍价格", true, ismoneyness).Value;
//高障碍价格
td.BarrierHigh = reader.GetDoubleOrPercent("高障碍价格", false, ismoneyness) ?? 0;
//高行权价
td.StrikeHigh = reader.GetDoubleOrPercent("高行权价", false, ismoneyness);
//补偿金额
td.Rebate = td.RebateRate = reader.GetDoubleOrPercent("补偿金额", false, isPremiumRate);
//高障碍补偿金额
td.RebateHigh = td.RebateHighRate = reader.GetDoubleOrPercent("高障碍补偿金额", false, isPremiumRate);
//观察方式
td.MonitorType = reader.GetString("观察方式");
//高参与率(百分比格式)
td.CallParticipationRate = reader.GetPercent("高参与率") ?? 0;
if (td.CallParticipationRate.HasValue && td.CallParticipationRate.Value < 0)
{
throw new ServiceException("[双鲨期权]高参与率 不能小于0,当前填写值:" + td.CallParticipationRate);
}
//低参与率(百分比格式)
td.PutParticipationRate = reader.GetPercent("低参与率") ?? 0;
if (td.PutParticipationRate.HasValue && td.PutParticipationRate.Value < 0)
{
throw new ServiceException("[双鲨期权]低参与率 不能小于0,当前填写值:" + td.PutParticipationRate);
}
//补偿支付
ReadRebateType(reader, td);
//观察频率
ReadObservationDates(reader, td);
}
//二元期权
private void ReadBinaryOption(DataRowReader reader, OtcOptionTradeFull td)
{
var isMoneyness = td.IsMoneynessOption == "是";
var isPremiumRate = td.IsUsePremiumRate == true;
//二元类型
td.PayoffType = reader.GetString("二元类型", true);
//补偿金额
td.CashOrNothingAmount = td.CashOrNothingAmountRate = reader.GetDoubleOrPercent("补偿金额", false, isPremiumRate);
//高障碍价格
td.BarrierHigh = reader.GetDoubleOrPercent("高障碍价格", false, isMoneyness) ?? 0;
//高障碍补偿金额
td.CashOrNothingAmountHigh = td.CashOrNothingAmountHighRate = reader.GetDoubleOrPercent("高障碍补偿金额", false, isPremiumRate);
td.MonitorType = reader.GetString("观察方式");
//补偿按敲出日年化
td.RebateAnnualizedAtKO = reader.GetString("补偿按敲出日年化") == "是";
//补偿计息规则
td.RebateDayCount = reader.GetString("补偿计息规则") ?? "";
//补偿支付
ReadRebateType(reader, td);
}
//区间累积期权
private void ReadRangeAccOption(DataRowReader reader, OtcOptionTradeFull td)
{
var isMoneyness = td.IsMoneynessOption == "是";
//区间下限
td.LowerRange = reader.GetDoubleOrPercent("区间下限", true, isMoneyness).Value;
//区间上限
td.UpperRange = reader.GetDoubleOrPercent("区间上限", true, isMoneyness).Value;
//区间收益
td.BonusRate = reader.GetPercent("区间收益") ?? 0;
//观察频率
ReadObservationDates(reader, td);
}
//气囊结构
private void ReadAirBagOption(DataRowReader reader, OtcOptionTradeFull td)
{
var isMoneyness = td.IsMoneynessOption == "是";
//障碍价格
td.BarrierLow = reader.GetDoubleOrPercent("障碍价格", true, isMoneyness).Value;
//是否离散观察
td.IsDiscreteMonitored = reader.GetString("是否离散观察") == "是";
//敲入参与率(百分比格式)
td.KIParticipationRate = reader.GetPercent("敲入参与率") ?? 0;
if (td.KIParticipationRate < 0)
{
throw new ServiceException("[气囊结构]敲入参与率 不能小于0,当前填写值:" + td.KIParticipationRate);
}
//非敲入参与率
td.NotKIParticipationRate = reader.GetPercent("未敲入参与率") ?? 0;
if (td.NotKIParticipationRate.HasValue && td.NotKIParticipationRate.Value < 0)
{
throw new ServiceException("[气囊结构]非敲入参与率 不能小于0,当前填写值:" + td.NotKIParticipationRate);
}
//收益封顶
td.HasPayoffLimit = reader.GetString("收益封顶") == "是";
if (td.HasPayoffLimit)
{
//收益封顶价格
td.HighStrike = reader.GetDoubleOrPercent("收益封顶价格", false, isMoneyness) ?? 0;
}
}
//凤凰期权
private void ReadAutoCallOption(DataRowReader reader, OtcOptionTradeFull td)
{
var isMoneyness = td.IsMoneynessOption == "是";
//票息是否年化
td.IsFixedCoupon = reader.GetString("票息年化") != "是";
//票息率
td.Coupon = reader.GetPercent("票息率") ?? 0;
//票息障碍价格
td.CouponBarrier = reader.GetDoubleOrPercent("票息障碍价格", false, isMoneyness) ?? 0;
//票息日历规则
td.CouponDayCount = reader.GetString("票息日历规则");
//票息结算方式
var couponPayType = reader.GetString("票息结算方式");
switch (couponPayType)
{
case "产生时支付":
td.CouponPayType = CouponPayTypeEnum.AtCreated;
break;
case "敲出时支付":
td.CouponPayType = CouponPayTypeEnum.AtKnockout;
break;
case "期末支付":
td.CouponPayType = CouponPayTypeEnum.AtMaturity;
break;
default:
if (!string.IsNullOrEmpty(couponPayType))
{
throw new ServiceException("[凤凰期权]票息结算方式 填写错误:" + couponPayType);
}
break;
}
td.CouponIncludeStartDate = reader.GetString("票息包含首日") == "是";
td.CouponUsePaymentDate = reader.GetString("使用支付日计息") == "是";
//敲出障碍价格
td.KOBarrier = reader.GetDoubleOrPercent("敲出障碍价格", true, isMoneyness) ?? 0;
//敲入障碍价格
td.KIBarrier = reader.GetDoubleOrPercent("敲入障碍价格", false, isMoneyness) ?? 0;
if (td.CouponPayType != CouponPayTypeEnum.AtMaturity && reader.GetString("敲入到期是否支付票息") == "否")
{
throw new ServiceException("只有期末支付时,【敲入到期是否支付票息】可以填否");
}
//敲入到期是否支付票息(期末支付时可以选择否)
td.IncludeCouponAfterKI = td.CouponPayType != CouponPayTypeEnum.AtMaturity || reader.GetString("敲入到期是否支付票息") == "是";
//敲入到期支付类别
var kiPayoffType = reader.GetString("敲入到期支付类别");
switch (kiPayoffType)
{
case "敲入转看跌":
td.KIPayoffType = KIPayoffTypeEnum.ToPutOption;
break;
case "敲入转熊市价差":
td.KIPayoffType = KIPayoffTypeEnum.ToPutSpreadOption;
break;
case "敲入转看涨":
td.KIPayoffType = KIPayoffTypeEnum.ToCallOption;
break;
case "敲入转牛市价差":
td.KIPayoffType = KIPayoffTypeEnum.ToCallSpreadOption;
break;
default:
if (!string.IsNullOrEmpty(kiPayoffType))
{
throw new ServiceException("[凤凰期权]敲入到期支付类别 填写错误:" + kiPayoffType);
}
break;
}
//敲入行权价
td.Strike = td.SpreadStrike1 = reader.GetDoubleOrPercent("敲入行权价", false, isMoneyness) ?? 0;
//封顶/封底行权价
if (td.KIPayoffType == KIPayoffTypeEnum.ToPutSpreadOption || td.KIPayoffType == KIPayoffTypeEnum.ToCallSpreadOption)
{
td.SpreadStrike = reader.GetDoubleOrPercent("封顶/封底行权价", false, isMoneyness) ?? 0;
}
//敲出观察频率
ReadKOObservationDates(reader, td);
//敲入观察频率
ReadObservationDates(reader, td);
//年化系数在保存类中检查转换
}
//雪球期权
private void ReadSnowBallOption(DataRowReader reader, OtcOptionTradeFull td)
{
var isMoneyness = td.IsMoneynessOption == "是";
//敲出障碍价格
td.KOBarrier = reader.GetDoubleOrPercent("敲出障碍价格", true, isMoneyness) ?? 0;
//敲出赔付类别
var koPayoffType = reader.GetString("敲出赔付类别");
switch (koPayoffType)
{
case "票息补偿":
td.KOPayoffType = KOPayoffTypeEnum.Rebate;
td.IsFixedCoupon = reader.GetString("票息年化") != "是";
td.KORebate = reader.GetPercent("票息率") ?? 0;
td.CouponDayCount = reader.GetString("票息日历规则");
td.AnnualizedPremiumRate = reader.GetPercent("年化期权费率");
td.CouponIncludeStartDate = reader.GetString("票息包含首日") == "是";
td.CouponUsePaymentDate = reader.GetString("使用支付日计息") == "是";
break;
case "敲出转期权":
td.KOPayoffType = KOPayoffTypeEnum.ToOption;
td.SpreadStrikeAtKO1 = reader.GetDoubleOrPercent("敲出行权价1", true, isMoneyness) ?? 0;
break;
case "敲出转看涨":
if (!ConsGlobal.CallPut.IsCall(td.CallPut))
{
throw new ServiceException("[雪球期权]敲出赔付类别 看跌时不支持:敲出转看涨");
}
td.KOPayoffType = KOPayoffTypeEnum.ToOption;
td.SpreadStrikeAtKO1 = reader.GetDoubleOrPercent("敲出行权价1", true, isMoneyness) ?? 0;
break;
case "敲出转看跌":
if (ConsGlobal.CallPut.IsCall(td.CallPut))
{
throw new ServiceException("[雪球期权]敲出赔付类别 看涨时不支持:敲出转看跌");
}
td.KOPayoffType = KOPayoffTypeEnum.ToOption;
td.SpreadStrikeAtKO1 = reader.GetDoubleOrPercent("敲出行权价1", true, isMoneyness) ?? 0;
break;
case "敲出转价差期权":
td.KOPayoffType = KOPayoffTypeEnum.ToSpreadOption;
td.SpreadStrikeAtKO1 = reader.GetDoubleOrPercent("敲出行权价1", true, isMoneyness) ?? 0;
td.SpreadStrikeAtKO = reader.GetDoubleOrPercent("敲出行权价2", true, isMoneyness) ?? 0;
break;
case "敲出转牛市价差":
if (!ConsGlobal.CallPut.IsCall(td.CallPut))
{
throw new ServiceException("[雪球期权]敲出赔付类别 看跌时不支持:敲出转牛市价差");
}
td.KOPayoffType = KOPayoffTypeEnum.ToSpreadOption;
td.SpreadStrikeAtKO1 = reader.GetDoubleOrPercent("敲出行权价1", true, isMoneyness) ?? 0;
td.SpreadStrikeAtKO = reader.GetDoubleOrPercent("敲出行权价2", true, isMoneyness) ?? 0;
break;
case "敲出转熊市价差":
if (ConsGlobal.CallPut.IsCall(td.CallPut))
{
throw new ServiceException("[雪球期权]敲出赔付类别 看涨时不支持:敲出转熊市价差");
}
td.KOPayoffType = KOPayoffTypeEnum.ToSpreadOption;
td.SpreadStrikeAtKO1 = reader.GetDoubleOrPercent("敲出行权价1", true, isMoneyness) ?? 0;
td.SpreadStrikeAtKO = reader.GetDoubleOrPercent("敲出行权价2", true, isMoneyness) ?? 0;
break;
default:
if (!string.IsNullOrEmpty(koPayoffType))
{
throw new ServiceException("[雪球期权]票息结算方式 填写错误:" + koPayoffType);
}
break;
}
//敲出支付方式
var koRebateType = reader.GetString("敲出支付方式");
switch (koRebateType)
{
case "立即支付":
td.KORebateType = RebateTypeEnum.AtHit;
break;
case "递延至期末支付":
td.KORebateType = RebateTypeEnum.AtEnd;
break;
default:
if (!string.IsNullOrEmpty(koRebateType))
{
throw new ServiceException("[雪球期权]敲出支付方式 填写错误:" + koRebateType);
}
break;
}
//票息支付日期
//td.KOObservationSettleDates = reader.GetString("票息支付日期");
//if (!string.IsNullOrWhiteSpace(td.KOObservationSettleDates))
//{
// td.KOObservationSettleDates = Regex.Replace(td.KOObservationSettleDates, "\\s0+:00:00", "");
//}
//初始敲入状态
td.IsInitialKnockedIn = reader.GetString("初始敲入") == "是";
//敲入障碍价格
td.KIBarrier = reader.GetDoubleOrPercent("敲入障碍价格", false, isMoneyness) ?? 0;
//敲入到期支付类别
var kiPayoffType = reader.GetString("敲入到期支付类别");
switch (kiPayoffType)
{
case "无":
if (td.IsInitialKnockedIn)
{
throw new ServiceException("[雪球期权]敲入到期支付类别 初始敲入为是时不支持:无");
}
td.KIPayoffType = KIPayoffTypeEnum.None;
break;
case "敲入转看跌":
if (!ConsGlobal.CallPut.IsCall(td.CallPut))
{
throw new ServiceException("[雪球期权]敲入到期支付类别 看跌时不支持:敲入转看跌");
}
td.KIPayoffType = KIPayoffTypeEnum.ToPutOption;
td.Strike = td.SpreadStrike1 = reader.GetDoubleOrPercent("敲入行权价", false, isMoneyness) ?? 0;
break;
case "敲入转熊市价差":
if (!ConsGlobal.CallPut.IsCall(td.CallPut))
{
throw new ServiceException("[雪球期权]敲入到期支付类别 看跌时不支持:敲入转熊市价差");
}
td.KIPayoffType = KIPayoffTypeEnum.ToPutSpreadOption;
td.Strike = td.SpreadStrike1 = reader.GetDoubleOrPercent("敲入行权价", false, isMoneyness) ?? 0;
td.SpreadStrike = reader.GetDoubleOrPercent("封顶/封底行权价", false, isMoneyness) ?? 0;
break;
case "敲入转看涨":
if (ConsGlobal.CallPut.IsCall(td.CallPut))
{
throw new ServiceException("[雪球期权]敲入到期支付类别 看涨时不支持:敲入转看涨");
}
td.KIPayoffType = KIPayoffTypeEnum.ToCallOption;
td.Strike = td.SpreadStrike1 = reader.GetDoubleOrPercent("敲入行权价", false, isMoneyness) ?? 0;
break;
case "敲入转牛市价差":
if (ConsGlobal.CallPut.IsCall(td.CallPut))
{
throw new ServiceException("[雪球期权]敲入到期支付类别 看涨时不支持:敲入转牛市价差");
}
td.KIPayoffType = KIPayoffTypeEnum.ToCallSpreadOption;
td.Strike = td.SpreadStrike1 = reader.GetDoubleOrPercent("敲入行权价", false, isMoneyness) ?? 0;
td.SpreadStrike = reader.GetDoubleOrPercent("封顶/封底行权价", false, isMoneyness) ?? 0;
break;
default:
if (!string.IsNullOrEmpty(kiPayoffType))
{
throw new ServiceException("[雪球期权]敲入到期支付类别 填写错误:" + kiPayoffType);
}
break;
}
//红利票息
td.Coupon = reader.GetDoubleOrPercent("红利票息", false, isMoneyness) ?? 0;
//敲出观察频率
ReadKOObservationDates(reader, td);
//敲入观察频率
ReadObservationDates(reader, td);
//年化系数在保存类中检查转换
}
//累计期权 三段式
private void ReadAccumulatorOptionSegmented(DataRowReader reader, OtcOptionTradeFull td)
{
var isMoneyness = td.IsMoneynessOption == "是";
td.AccumulatorStructureType = AccumulatorStructureTypeEnum.Segmented;
td.AccumuTradeAmount = reader.GetDouble("沽购数量") ?? 0;
//执行价2
td.Strike2 = reader.GetDoubleOrPercent("执行价2", true, isMoneyness) ?? 0;
//执行价3
td.Strike3 = reader.GetDoubleOrPercent("执行价3", true, isMoneyness) ?? 0;
//敲出障碍价格
td.KOBarrier = reader.GetDoubleOrPercent("敲出障碍价格", true, isMoneyness) ?? 0;
//上端收益类型
var payType = reader.GetString("上端收益类型");
switch (payType)
{
case "浮动":
td.PayoffType = "浮动";
break;
case "固定(票息)":
td.PayoffType = "固定";
break;
default:
if (!string.IsNullOrEmpty(payType))
{
throw new ServiceException("[累计期权三段式]上端收益类型 填写错误:" + payType);
}
td.PayoffType = "浮动";
break;
}
if (td.PayoffType == "固定")
{
//票息率
td.Coupon = reader.TryGetDoubleOrPercent("票息1", true, out var percent) ?? 0;
td.Coupon2 = reader.TryGetDoubleOrPercent("票息2", true, out var percent1) ?? 0;
td.CouponPercent = percent;
//票息是否年化
td.IsFixedCoupon = reader.GetString("票息年化") != "是";
//票息日历规则
td.CouponDayCount = reader.GetString("票息日历规则");
//乘数1
td.Multiplier = reader.GetDouble("乘数1", false) ?? 0;
//乘数2
td.Multiplier2 = reader.GetDouble("乘数2", false) ?? 0;
//乘数3
td.Multiplier3 = reader.GetDouble("乘数3", false) ?? 0;
}
else
{
//乘数1
td.Multiplier = reader.GetDouble("乘数1", false) ?? 1;
if (td.Multiplier <= 0)
{
throw new ServiceException("[累计期权三段式]乘数1不能小于等于0 填写错误:" + td.Multiplier);
}
//乘数2
td.Multiplier2 = reader.GetDouble("乘数2", false) ?? 1;
if (td.Multiplier2 <= 0)
{
throw new ServiceException("[累计期权三段式]乘数2不能小于等于0 填写错误:" + td.Multiplier2);
}
//乘数3
td.Multiplier3 = reader.GetDouble("乘数3", false) ?? 1;
if (td.Multiplier3 <= 0)
{
throw new ServiceException("[累计期权三段式]乘数3不能小于等于0 填写错误:" + td.Multiplier3);
}
}
//敲出是否终止
td.EarlyTerminate = reader.GetString("敲出是否终止") == "是";
//结算方式
var settlementMode = reader.GetString("结算方式1");
switch (settlementMode)
{
case "现金当日":
case "现金结算(当日)":
td.SettlementMode = "现金当日";
break;
case "实物交割":
td.SettlementMode = "实物交割";
break;
case "现金实物合并结算":
td.SettlementMode = "现金实物合并结算";
break;
default:
if (!string.IsNullOrEmpty(settlementMode))
{
throw new ServiceException("[累计期权三段式]结算方式1 填写错误:" + settlementMode);
}
td.SettlementMode = "现金当日";
break;
}
DictionarySerivice dictionarySerivice = new DictionarySerivice();
var dic = dictionarySerivice.GetForwardDateDic();
if (td.SettlementMode == "实物交割" || td.SettlementMode == "现金实物合并结算")
{
td.ForwardPriceType = reader.GetString("远期期初价类型1");
td.ForwardDateType = reader.GetString("远期到期日类型1");
if (td.ForwardDateType != "标的到期日" && td.ForwardDateType != "期权到期日")
{
var dicModel = dic.FirstOrDefault(l => l.Value == td.ForwardDateType);
if (dicModel.Value == null || dicModel.Value == "") { throw new ServiceException("[累计期权三段式]远期到期日类型1 系统中未找到:" + td.ForwardDateType); }
}
}
var settlementMode2 = reader.GetString("结算方式2");
switch (settlementMode2)
{
case "现金当日":
case "现金结算(当日)":
td.SettlementMode2 = "现金当日";
break;
case "实物交割":
td.SettlementMode2 = "实物交割";
break;
case "现金实物合并结算":
td.SettlementMode2 = "现金实物合并结算";
break;
default:
if (!string.IsNullOrEmpty(settlementMode2))
{
throw new ServiceException("[累计期权三段式]结算方式2 填写错误:" + settlementMode2);
}
td.SettlementMode2 = "现金当日";
break;
}
td.ForwardPriceType2 = reader.GetString("远期期初价类型2");
td.ForwardDateType2 = reader.GetString("远期到期日类型2");
if (td.SettlementMode2 == "实物交割" || td.SettlementMode2 == "现金实物合并结算")
{
if (td.ForwardDateType2 != "标的到期日" && td.ForwardDateType2 != "期权到期日")
{
var dicModel = dic.FirstOrDefault(l => l.Value == td.ForwardDateType2);
if (dicModel.Value == null || dicModel.Value == "") { throw new ServiceException("[累计期权三段式]远期到期日类型2 系统中未找到:" + td.ForwardDateType2); }
}
}
//结算方式
var settlementMode3 = reader.GetString("结算方式3");
switch (settlementMode3)
{
case "现金当日":
case "现金结算(当日)":
td.SettlementMode3 = "现金当日";
break;
case "实物交割":
td.SettlementMode3 = "实物交割";
break;
case "现金实物合并结算":
td.SettlementMode3 = "现金实物合并结算";
break;
default:
if (!string.IsNullOrEmpty(settlementMode3))
{
throw new ServiceException("[累计期权三段式]结算方式3 填写错误:" + settlementMode3);
}
td.SettlementMode3 = "现金当日";
break;
}
if (td.SettlementMode3 == "实物交割" || td.SettlementMode3 == "现金实物合并结算")
{
td.ForwardPriceType3 = reader.GetString("远期期初价类型3");
td.ForwardDateType3 = reader.GetString("远期到期日类型3");
if (td.ForwardDateType3 != "标的到期日" && td.ForwardDateType3 != "期权到期日")
{
var dicModel = dic.FirstOrDefault(l => l.Value == td.ForwardDateType3);
if (dicModel.Value == null || dicModel.Value == "") { throw new ServiceException("[累计期权三段式]远期到期日类型3 系统中未找到:" + td.ForwardDateType3); }
}
}
//敲出观察频率
ReadKOObservationDates(reader, td);
//保存 还是 用累计期权 保存 只不过 导入时取对应三段式列时需要判断
td.TradeType = "累计期权";
}
//累计期权
private void ReadAccumulatorOption(DataRowReader reader, OtcOptionTradeFull td)
{
var isMoneyness = td.IsMoneynessOption == "是";
td.AccumulatorStructureType = AccumulatorStructureTypeEnum.Standard;
td.AccumuTradeAmount = reader.GetDouble("沽购数量") ?? 0;
//敲出障碍价格
td.KOBarrier = reader.GetDoubleOrPercent("敲出障碍价格", true, isMoneyness) ?? 0;
//上端收益类型
var payType = reader.GetString("上端收益类型");
switch (payType)
{
case "浮动":
td.PayoffType = "浮动";
break;
case "固定(票息)":
td.PayoffType = "固定";
break;
default:
if (!string.IsNullOrEmpty(payType))
{
throw new ServiceException("[累计期权]上端收益类型 填写错误:" + payType);
}
td.PayoffType = "浮动";
break;
}
if (td.PayoffType == "固定")
{
//票息率
td.Coupon = reader.TryGetDoubleOrPercent("票息", true, out var percent) ?? 0;
td.CouponPercent = percent;
//票息是否年化
td.IsFixedCoupon = reader.GetString("票息年化") != "是";
//票息日历规则
td.CouponDayCount = reader.GetString("票息日历规则");
}
//杠杆倍数
if (PS.Config.ErpElement.AccumulatorShowMultiplier1)
{
td.CallMultiplier = td.PutMultiplier = 1;
var multiplier = reader.GetDouble("杠杆倍数", false) ?? 1;
if (multiplier <= 0)
{
throw new ServiceException("[累计期权]杠杆倍数不能小于等于0 填写错误:" + multiplier);
}
if (ConsGlobal.CallPut.IsCall(td.CallPut))
{
td.PutMultiplier = multiplier;
}
else
{
td.CallMultiplier = multiplier;
}
}
else
{
//看涨乘数
td.CallMultiplier = reader.GetDouble("看涨乘数", false) ?? 1;
if (td.CallMultiplier <= 0)
{
throw new ServiceException("[累计期权]看涨乘数不能小于等于0 填写错误:" + td.CallMultiplier);
}
//看跌乘数
td.PutMultiplier = reader.GetDouble("看跌乘数", false) ?? 1;
if (td.PutMultiplier <= 0)
{
throw new ServiceException("[累计期权]看跌乘数不能小于等于0 填写错误:" + td.PutMultiplier);
}
}
//结算方式
var settlementMode = reader.GetString("结算方式");
switch (settlementMode)
{
case "现金当日":
case "现金结算(当日)":
td.SettlementMode = "现金当日";
break;
case "现金期末":
case "现金结算(期末)":
td.SettlementMode = "现金期末";
td.AccumuType = reader.GetString("累计类型") ?? "";
if (!string.IsNullOrWhiteSpace(td.AccumuType) && td.AccumuType != "子弹")
{
throw new ServiceException("[累计期权]结算方式 填写错误:" + td.AccumuType);
}
break;
case "实物交割":
td.SettlementMode = "实物交割";
td.AccumuType = reader.GetString("累计类型") ?? "";
if (!string.IsNullOrWhiteSpace(td.AccumuType) && td.AccumuType != "区间现金结算")
{
throw new ServiceException("[累计期权]结算方式 填写错误:" + td.AccumuType);
}
break;
case "现金实物合并结算":
td.SettlementMode = "现金实物合并结算";
td.AccumuType = reader.GetString("累计类型") ?? "";
if (!string.IsNullOrWhiteSpace(td.AccumuType) && td.AccumuType != "区间现金结算")
{
throw new ServiceException("[累计期权]结算方式 填写错误:" + td.AccumuType);
}
break;
default:
if (!string.IsNullOrEmpty(settlementMode))
{
throw new ServiceException("[累计期权]结算方式 填写错误:" + settlementMode);
}
td.SettlementMode = "现金当日";
break;
}
if (td.SettlementMode == "实物交割" || td.SettlementMode == "现金实物合并结算")
{
DictionarySerivice dictionarySerivice = new DictionarySerivice();
var dic = dictionarySerivice.GetForwardDateDic();
td.ForwardPriceType = reader.GetString("远期期初价类型");
td.ForwardDateType = reader.GetString("远期到期日类型");
if (td.ForwardDateType != "标的到期日" && td.ForwardDateType != "期权到期日")
{
var dicModel = dic.FirstOrDefault(l => l.Value == td.ForwardDateType);
if (dicModel.Value == null || dicModel.Value == "") { throw new ServiceException("[累计期权]远期到期日类型 系统中未找到:" + td.ForwardDateType); }
}
}
//敲出是否终止
td.EarlyTerminate = reader.GetString("敲出是否终止") == "是";
//敲出观察频率
ReadKOObservationDates(reader, td);
}
//现金流交易
private void ReadCashFlow(DataRowReader reader, OtcOptionTradeFull td)
{
td.CouponDayCount = reader.GetString("计息日历规则");
td.ProfitRate = reader.GetPercent("利率") ?? 0;
var rateType = reader.GetString("利率类型");
switch (rateType)
{
case "实际利率":
td.RateType = CashFlowRateTypeEnum.实际利率;
break;
case "年化利率":
td.RateType = CashFlowRateTypeEnum.年化利率;
break;
default:
break;
}
td.PrepayRatio = reader.GetPercent("返还比例") ?? 0;
var depositType = reader.GetString("资金类型");
switch (depositType)
{
case "成本摊还":
td.DepositType = CashflowDepositTypeEnum.成本摊还;
break;
case "资金收益":
td.DepositType = CashflowDepositTypeEnum.资金收益;
break;
default:
break;
}
}
//自定义交易
private void ReadCustomizedOption(DataRowReader reader, OtcOptionTradeFull td)
{
var dicInfo = new StructureService(OptUser).QueryStructureMap(td.IsGroup > 0 ? StructureRangeEnum.BALCK_TRADE : StructureRangeEnum.CUSTOM_TRADE);
if (!dicInfo.TryGetValue(td.StructureType ?? td.TradeType, out var dictionaryNames))
{
return;
}
var propertys = new List<ExtendInfoModel>();
dictionaryNames.ForEach(x =>
{
string value = null;
switch (x.ColumnType)
{
case StructureColumnTypeEnum.NUMBER:
value = reader.GetDouble(x.ColumnName)?.ToString("0.########");
break;
case StructureColumnTypeEnum.DATE:
value = reader.GetDate(x.ColumnName)?.ToString("yyyy-MM-dd");
break;
case StructureColumnTypeEnum.COMBO_BOX_SINGLE:
value = reader.GetString(x.ColumnName);
break;
case StructureColumnTypeEnum.TEXT:
default:
value = reader.GetString(x.ColumnName);
break;
}
if (!string.IsNullOrWhiteSpace(value))
{
propertys.Add(new ExtendInfoModel()
{
name = x.ColumnName,
value = value
});
}
});
td.ExtendInfo = JsonHelper.Serialize(propertys);
}
//Risky
private void ReadRisky(DataRowReader reader, OtcOptionTradeFull td)
{
//执行价格(亚式浮动行权价类型时非必填)
td.Strike1 = td.Strike;
td.Strike2 = reader.GetDoubleOrPercent("执行价格2", true, td.IsMoneynessOption == "是");
td.Strike3 = reader.GetDoubleOrPercent("执行价格3", true, td.IsMoneynessOption == "是");
td.ParticipationRate1 = td.ParticipationRate.Value;
td.ParticipationRate2 = reader.GetPercent("参与率2", true) ?? 0;
td.ParticipationRate3 = reader.GetPercent("参与率3", true) ?? 0;
td.ParticipationRate = 1;
td.PremiumPayDate = td.ExerciseDate;
}
//读取补偿支付
private void ReadRebateType(DataRowReader reader, OtcOptionTradeFull td)
{
td.RebateType = reader.GetString("补偿支付");
switch (td.RebateType)
{
case "立即":
td.RebateType = "AtHit";
break;
case "递延":
td.RebateType = "AtEnd";
break;
case "AtHit":
case "AtEnd":
break;
default:
td.RebateType = string.IsNullOrWhiteSpace(td.RebateType)
? "AtHit" : throw new ServiceException($"[{td.TradeType}]补偿支付 填写错误,不支持:{td.RebateType}");
break;
}
}
//读取敲入观察频率
private void ReadObservationDates(DataRowReader reader, OtcOptionTradeFull td)
{
var topType = reader.TopType;
reader.SetTopType("敲入观察日设置");
td.ObservationDates = reader.GetString("自定义观察日");
if (string.IsNullOrWhiteSpace(td.ObservationDates))
{
var ruleStr = reader.GetString("使用规则生成观察日");
td.ObservationDates = GenObservationDatesByRule(td, ruleStr);
}
else
{
var observationDates = td.ObservationDates.Replace('/', '-').Split(',').Select(O => O.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries)[0]);
td.ObservationDates = string.Join(",", observationDates);
if (td.ObservationDates.Split(',').Any(n => !DateTime.TryParse(n, out _)))
{
throw new ServiceException($"[{td.TradeType}][敲入观察日设置]自定义观察日 填写错误:不符合要求的格式");
}
if (td.ObservationDates.Split(',').Any(n =>
{
DateTime.TryParse(n, out var date);
return QdpCalendarHelper.IsHoliday(date);
}))
{
throw new ServiceException($"[{td.TradeType}][敲入观察日设置]自定义观察日 填写错误:观察日存在非交易日,导入失败");
}
#region 导入时,写入敲入观察频率
string termStr = null;
var ruleStr = reader.GetString("使用规则生成观察日");
if (!string.IsNullOrWhiteSpace(ruleStr))
{
switch (ruleStr)
{
case "每日":
termStr = "1D";
break;
case "每周":
termStr = "1W";
break;
case "每月":
termStr = "1M";
break;
case "每年":
termStr = "1Y";
break;
}
if (termStr == null)
{
var strs = ruleStr.Split(new[] { ',' });
termStr = strs[0].Trim();
}
//敲入观察周期写入metadic中
td.MetaDic["敲入观察周期"] = termStr;
}
#endregion
}
reader.SetTopType(topType);
}
//读取观察日设置并生成观察日列表
private static string GenObservationDatesByRule(OtcOptionTradeFull td, string ruleStr, bool isKO = false)
{
if (string.IsNullOrWhiteSpace(ruleStr))
{
return null;
}
string termStr = null;
var dayConvention = BusinessDayConvention.Following; //假日调整
var alignEnd = true; //是否向到期日对齐
switch (ruleStr)
{
case "每日":
termStr = "1D";
break;
case "每周":
termStr = "1W";
break;
case "每月":
termStr = "1M";
break;
case "每年":
termStr = "1Y";
break;
}
var kstr = isKO ? "敲出" : "敲入";
if (termStr == null)
{
var strs = ruleStr.Split(new[] { ',' });
termStr = strs[0].Trim();
if (!Term.IsTerm(termStr))
{
throw new ServiceException($"[{td.TradeType}][{kstr}观察日设置]使用规则生成观察日 观察日间隔填写错误");
}
//假日调整
if (strs.Length > 1)
{
var observationHolidayType = strs[1];
switch (observationHolidayType)
{
case "向后调整":
dayConvention = BusinessDayConvention.Following;
break;
case "向前调整":
dayConvention = BusinessDayConvention.Previous;
break;
case "不调整":
dayConvention = BusinessDayConvention.None;
break;
default:
dayConvention = string.IsNullOrWhiteSpace(observationHolidayType)
? BusinessDayConvention.Following
: throw new ServiceException($"[{td.TradeType}][{kstr}观察日设置]使用规则生成观察日 假日调整填写错误,不支持:" + observationHolidayType);
break;
}
}
//对齐规则
if (strs.Length > 2)
{
var alignEndStr = strs[2];
switch (alignEndStr)
{
case "向开始日对齐":
case "向到期日对齐":
break;
default:
alignEndStr = string.IsNullOrWhiteSpace(alignEndStr) ? "向开始日对齐"
: throw new ServiceException($"[{td.TradeType}][{kstr}观察日设置]使用规则生成观察日 对齐规则填写错误,不支持:" + alignEndStr);
break;
}
alignEnd = alignEndStr == "向到期日对齐";
}
}
//敲入观察周期写入metadic中
if (!isKO)
{
td.MetaDic["敲入观察周期"] = termStr;
}
else if (isKO)
{
td.MetaDic["敲出观察周期"] = termStr;
}
return QdpObservationHelper.GetObservationDateString(td.TradeDate.Value, td.ExerciseDate.Value, termStr, dayConvention, alignEnd);
}
//读取敲出观察频率
private void ReadKOObservationDates(DataRowReader reader, OtcOptionTradeFull td)
{
var topType = reader.TopType;
reader.SetTopType("敲出观察日设置");
var separators = new[] { ',', ';', '', '' };
List<string> obDateList, stDateList;
string[] barriePrices, coupons;
//观察日
var obDatesStr = reader.GetString("观察日");
if (string.IsNullOrWhiteSpace(obDatesStr))
{
var ruleStr = reader.GetString("敲出观察频率");
td.KOObservationDates = GenObservationDatesByRule(td, ruleStr, true);
//结算日期
var stDatesStr = reader.GetString("结算日期");
if (string.IsNullOrWhiteSpace(stDatesStr))
{
if (!string.IsNullOrEmpty(td.KOObservationDates))
{
td.KOObservationSettleDates = td.KOObservationDates;
}
}
if (!string.IsNullOrEmpty(td.KOObservationDates))
{
var odNum = td.KOObservationDates.Split(",").Count();
var koBarrierStr = "";
var koKORebate = "";
for (var i = 0; i < odNum; i++)
{
koBarrierStr += td.KOBarrier + ",";
koKORebate += "0,";
}
if (!string.IsNullOrEmpty(koBarrierStr))
{
koBarrierStr = koBarrierStr.Substring(0, koBarrierStr.Length - 1);
}
if (!string.IsNullOrEmpty(koKORebate) && !td.TradeType.Contains("累计"))
{
koKORebate = koKORebate.Substring(0, koKORebate.Length - 1);
}
td.KOObservationDates += ";" + koBarrierStr + (!td.TradeType.Contains("累计")?(";" + koKORebate):"");
}
}
else
{
td.MetaDic["敲出观察周期"] = "1D";
var strArr = obDatesStr.Split(separators, StringSplitOptions.RemoveEmptyEntries);
obDateList = new List<string>(strArr.Length);
foreach (var str in strArr)
{
if (DateTime.TryParse(str, out var dt))
{
obDateList.Add(dt.ToString("yyyy-MM-dd"));
if (dt < td.TradeDate.Value)
{
throw new ServiceException($"[{td.TradeType}][敲出观察日设置]观察日期 填写错误,观察日期'{str}'不能小于开始日期'{td.TradeDate.Value:yyyy-MM-dd}'");
}
if (dt > td.ExerciseDate.Value)
{
throw new ServiceException($"[{td.TradeType}][敲出观察日设置]观察日期 填写错误,观察日期'{str}'不能大于到期日期'{td.ExerciseDate.Value:yyyy-MM-dd}'");
}
if (QdpCalendarHelper.IsHoliday(dt))
{
throw new ServiceException($"[{td.TradeType}][敲出观察日设置]观察日期 填写错误,存在非交易日'{str}'");
}
}
else
{
throw new ServiceException($"[{td.TradeType}][敲出观察日设置]观察日期 填写错误,日期'{str}'未能解析成功");
}
}
//结算日期
var stDatesStr = reader.GetString("结算日期");
if (string.IsNullOrWhiteSpace(stDatesStr))
{
stDateList = obDateList;
}
else
{
strArr = stDatesStr.Split(separators, StringSplitOptions.RemoveEmptyEntries);
stDateList = new List<string>(strArr.Length);
foreach (var str in strArr)
{
if (DateTime.TryParse(str, out var dt))
{
stDateList.Add(dt.ToString("yyyy-MM-dd"));
if (dt < td.TradeDate.Value)
{
throw new ServiceException($"[{td.TradeType}][敲出观察日设置]结算日期 填写错误,日期'{str}'不能小于开始日期'{td.TradeDate.Value:yyyy-MM-dd}'");
}
}
else
{
throw new ServiceException($"[{td.TradeType}][敲出观察日设置]结算日期 填写错误,日期'{str}'未能解析成功");
}
}
if (stDateList.Count != obDateList.Count)
{
throw new ServiceException($"[{td.TradeType}][敲出观察日设置]结算日期 列表数量应和观察日一致");
}
}
//障碍价格
var barriePricesStr = reader.GetString("障碍价格");
if (string.IsNullOrWhiteSpace(barriePricesStr))
{
barriePrices = obDateList.Select(n => td.KOBarrier.HasValue ? td.KOBarrier.Value.ToString("0.######") : string.Empty).ToArray();
}
else
{
if (td.TradeType == "凤凰期权")
{
barriePrices = barriePricesStr.Split(separators);
}
else
{
barriePrices = barriePricesStr.Split(separators, StringSplitOptions.RemoveEmptyEntries);
}
if (barriePrices.Length != obDateList.Count)
{
throw new ServiceException($"[{td.TradeType}][敲出观察日设置]障碍价格 列表数量应和观察日一致");
}
var converts = barriePrices.Select(str =>
{
var percent = str.EndsWith("%");
if (percent)
{
str = str.TrimEnd('%');
}
if (td.TradeType == "凤凰期权")
{
return double.TryParse(str, out var num) ? (percent ? num / 100 : num).ToString() : "";
}
else
{
return double.TryParse(str, out var num) ? (percent ? num / 100 : num).ToString() :
throw new ServiceException($"[{td.TradeType}][敲出观察日设置]障碍价格 数字填写错误");
}
}).ToArray();
barriePrices = converts.Select(n => string.IsNullOrEmpty(n) ? "" : Convert.ToDouble(n).ToString("0.######")).ToArray();
}
//票息率
var couponsStr = reader.GetString("票息率");
if (string.IsNullOrWhiteSpace(couponsStr))
{
var couponStr = (td.TradeType == "雪球期权" ? td.KORebate : td.Coupon).ToString("0.########");
if (couponStr.Length < 1)
{
couponStr = "0";
}
coupons = obDateList.Select(n => couponStr).ToArray();
}
else
{
coupons = couponsStr.Split(separators, StringSplitOptions.RemoveEmptyEntries);
if (coupons.Length != obDateList.Count)
{
throw new ServiceException($"[{td.TradeType}][敲出观察日设置]票息率 列表数量应和观察日一致");
}
var converts = coupons.Select(str =>
{
var percent = str.EndsWith("%");
if (percent)
{
str = str.TrimEnd('%');
}
return double.TryParse(str, out var num) ? (percent ? num / 100 : num) :
throw new ServiceException($"[{td.TradeType}][敲出观察日设置]票息率 数字填写错误");
}).ToArray();
coupons = converts.Select(n => n.ToString("0.########")).ToArray();
}
td.KOObservationDates = string.Join(";", new[] {
string.Join(",",obDateList),
string.Join(",",barriePrices),
string.Join(",",coupons)
});
td.KOObservationSettleDates = string.Join(",", stDateList);
}
reader.SetTopType(topType);
}
#endregion
#region---读取交易了结----
//了结信息
private TradeCloseRequestModel ReadCloseData(DataRowReader reader, OtcOptionTradeFull td)
{
reader.SetTopType("了结信息");
//了结方式
var closeType = reader.GetString("了结方式");
switch (closeType)
{
case "平仓":
break;
case "行权":
case "到期":
case "提前行权":
if (td.TradeType == "自定义交易")
{
throw new ServiceException("[了结信息]了结方式 填写错误,结构类型为'自定义交易'时仅支持'平仓',填写值为:" + closeType);
}
break;
default:
if (!string.IsNullOrWhiteSpace(closeType))
{
throw new ServiceException("[了结信息]了结方式 填写错误,不支持:" + closeType);
}
return null;
}
var model = new TradeCloseRequestModel
{
CloseType = closeType
};
//了结日期
model.CloseDate = model.CloseType == "到期" ? td.ExerciseDate.Value : reader.GetDate("了结日期") ?? td.ExerciseDate.Value;
//了结标的价格
model.UnderlyingPrice = reader.GetDouble("了结标的价格", "了结时标的价格", true).Value;
//行权标的均价
model.UnderlyingAvgPrice = reader.GetDouble("行权标的均价");
if (closeType == "平仓")
{
//平仓总额
model.UnwindTotalFee = reader.GetDouble("平仓总额");
if (!model.UnwindTotalFee.HasValue)
{
//平仓单价
model.UnwindPrice = reader.GetDouble("平仓单价");
//平仓单价比例
model.UnwindPriceRate = reader.GetDouble("平仓单价比例");
}
//平仓波动率
model.UnwindVolatility = reader.GetPercent("平仓波动率");
}
//导入了结方式为到期并且平仓总额不为空
if (closeType == "到期"&& reader.GetDouble("平仓总额")!=null)
{
//平仓总额
model.UnwindTotalFee = reader.GetDouble("平仓总额");
}
return model;
}
// 执行了结
private void ExecuteClose(trade dbTrade, TradeCloseRequestModel req)
{
if (req == null)
{
return;
}
dbTrade.TradeStatus = "确认成交";
var dbTradeCashList = DbContext.trade_cash.Where(t => t.TradeId == dbTrade.id && !t.IsDeleted).ToList();
var dbClientCashInOutList = DbContext.ClientCashInCashOut.Where(t => dbTrade.id == t.TradeId.Value).ToList();
DbContext.trade_cash.RemoveRange(dbTradeCashList);
var tradeCashIds = dbTradeCashList.Select(x => x.id);
var tradeCashDetials = DbContext.trade_cash_detail.Where(x => tradeCashIds.Contains(x.TradeCashId));
DbContext.trade_cash_detail.RemoveRange(tradeCashDetials);
DbContext.ClientCashInCashOut.RemoveRange(dbClientCashInOutList);
var newTC = new trade_cash
{
ValidState = "Valid",
OptId = UserId,
OptName = UserName,
OptDate = DateTime.Now,
Action = ClientCashInCashOut.系统操作_期权费,
ExceciseType = "现金",
TradeId = dbTrade.id,
ValueDate = dbTrade.TradeDate.Value,
Strike = dbTrade.IsMoneynessOptionData ? dbTrade.Strike * (dbTrade.SpotPrice ?? 0.0) : dbTrade.Strike,
Notional = dbTrade.Notional
};
var CountRatio = UnderlyingDataProvider.GetCountRatio(dbTrade.UnderlyingCode);
newTC.TradeAmount = newTC.Notional / CountRatio;
newTC.Amount = ((dbTrade.BuySell == "买入" ? -1 : 1) * dbTrade.TradePrice) ?? 0;
newTC.TradeType = dbTrade.BuySell;
newTC.Comments = "导入交易了结添加期权费";
DbContext.trade_cash.Add(newTC);
DbContext.SaveChanges();
if (dbTrade.PremiumPayDate.HasValue && dbTrade.PremiumPayDate > dbTrade.TradeDate)
{
newTC.Status = TradeCashStatusEnum.冻结;
}
else
{
var client = DataCacheProvider.GetClientDataSource().GetData(dbTrade.ClientId);
var newCC = new ClientCashInCashOut
{
Number = UniqueTimeId.GetStr(),
HappenDate = dbTrade.PremiumPayDate ?? dbTrade.TradeDate,
Action = ClientCashInCashOut.系统操作_期权费,
Direction = ClientCashInCashOut.应收,
OptDate = DateTime.Now,
OptId = UserId,
OptName = UserName,
CreateDate = DateTime.Now,
CreatorId = UserId,
CreatorName = UserName,
ClientId = dbTrade.ClientId,
ClientName = dbTrade.ClientName,
ClientNumber = client.Number,
TradeId = dbTrade.id,
TradeCashId = newTC.id,
Money = (dbTrade.BuySell == "买入" ? 1 : -1) * dbTrade.TradePrice,
ValidState = "Valid",
//权利金默认为应收 已执行
TradeNumber = dbTrade.TradeNumber,
IsGroup = dbTrade.IsGroup
};
//根据是否需要结算设置资金状态
newTC.Status = TradeCashStatusEnum.已执行;
newTC.SettleDate = newTC.ValueDate;
newCC.State = ClientCashInCashOut.已确认;
newCC.SettleDate = newTC.ValueDate;
DbContext.ClientCashInCashOut.Add(newCC);
}
DbContext.SaveChanges();
new TradeCashService(this).SaveTradeCashDetail(newTC);
req.ImportFlag = "交易导入";
req.SkipWorkflow = true;
req.TradeNumber = dbTrade.TradeNumber;
req.CloseTradeAmountRate = 1;
req.CloseTradeAmount = dbTrade.TradeAmount;
new OtcTradeCloseService(this).ExecuteClose(req, true);
}
#endregion
#region---内部业务类----
class DataRowReader
{
DataRow _row;
readonly Dictionary<string, int> _colMap;
public DataRowReader(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;
var customField = new List<string>();
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();
if (preCol1 == "自定义属性")
{
customField.Add(col2);
}
_colMap[preCol1 + col2] = index;
}
CustomField = customField.ToArray();
}
public string TopType { get; private set; }
/// <summary>
/// 自定义字段名
/// </summary>
public string[] CustomField { 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 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? TryGetDoubleOrPercent(string fieldName, bool required, out bool percent)
{
var str = GetString(fieldName, required);
if (!required && string.IsNullOrWhiteSpace(str))
{
percent = false;
return null;
}
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}");
}
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
/// <summary>
/// 组合销售提成信息
/// </summary>
private List<int> GetSalesIds(string salesmenNames)
{
var salesNameArr = salesmenNames.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
if (!salesNameArr.Any())
{
return null;
}
var salesDic = new SalesmenDataService(OptUser).GetSalesIdByNames(salesNameArr)
.ToDictionary(n => n.Name, n => n.id);
var results = new List<int>(salesNameArr.Length);
foreach (var name in salesNameArr)
{
if (!salesDic.TryGetValue(name, out var salesId))
{
throw new ServiceException(PS.Config.ErpElement.SaleMode == YLErp.Configuration.Enums.SaleMode.CustomerManager ? $"客户经理'{name}'未找到" : $"销售员'{name}'未找到");
}
results.Add(salesId);
}
return results;
}
private int GetClientId(string clientName)
{
if (string.IsNullOrWhiteSpace(clientName))
{
return 0;
}
var client = DataCacheProvider.GetClientDataSource().AsQueryable().FirstOrDefault(p => p.Name == clientName);
if (client != null)
{
return client.id;
}
return 0;
}
}
}