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
{
///
/// 场外交易导入服务
///
public class OtcTradeImportService : YLBaseService
{
public OtcTradeImportService(YLBaseService baseService) : base(baseService)
{
}
public OtcTradeImportService(OptUserInfo userInfo) : base(userInfo)
{
}
///
/// 从excel文件中导入场外期权交易
///
public void ImportOptionTradesFromExcel(Stream streamIn, out int totalNum, out int successNum)
{
new OtcOptionTradeImportService(this).ImportFromExcel(streamIn, out totalNum, out successNum);
}
///
/// 从excel文件中读取场外期权交易导入
///
public List ReadOptionTradesFromExcel(Stream streamIn)
{
return new OtcOptionTradeImportService(this).ReadFromExcel(streamIn);
}
}
///
/// 场外期权交易导入服务
///
class OtcOptionTradeImportService : OtcTradeSaveService
{
public OtcOptionTradeImportService(OptUserInfo userInfo) : base(userInfo)
{
}
public OtcOptionTradeImportService(YLBaseService baseService) : base(baseService)
{
}
private readonly ErpBaseContext basedb = new ErpBaseContext();
///
/// 导入交易
///
///
/// 当前文件中的目标期权总条数
/// 成功入库的数量
public void ImportFromExcel(Stream streamIn, out int totalNum, out int successNum)
{
totalNum = 0;
successNum = 0;
var rowIndex = 0;
var groupTradeList = new List();
var structureTradeList = new List();
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().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);
}
}
///
/// 导入交易
///
public List 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(table.Rows.Count);
foreach (var row in table.Rows.Cast().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 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 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();
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();
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(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();
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 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(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(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 _colMap;
public DataRowReader(DataTable table)
{
var colCount = table.Columns.Count;
_colMap = new Dictionary(colCount, StringComparer.OrdinalIgnoreCase);
var row1 = table.Rows[0];
var row2 = table.Rows[1];
var preCol1 = string.Empty;
var customField = new List();
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; }
///
/// 自定义字段名
///
public string[] CustomField { get; private set; }
///
/// 设置datarow
///
public void SetDataRow(DataRow row)
{
_row = row;
TopType = "基本要素";
}
///
/// 设置顶部类型
///
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}");
}
///
/// 获取日期(不包括时间)
///
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}");
}
///
///
///
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
///
/// 组合销售提成信息
///
private List 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(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;
}
}
}