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

897 lines
36 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 Org.BouncyCastle.Ocsp;
using System.Data;
using YLErp.BLL;
using YLErp.Commons;
using YLErp.Configuration.Enums;
using YLErp.DBModels;
using YLErp.DBModels.Enums;
using YLErp.DBModels.Helpers;
using YLErp.Helpers;
using YLErp.Model;
using YLErp.Model.Enum;
using YLErp.Modules.TradeModule.DealModule;
using YLErp.Modules.TradeModule.OrderModule;
using YLErp.QdpModule;
namespace YLErp.Modules.TradeModule.ForwardModule
{
public class ForwardTradeImportService : TradeCashService
{
public ForwardTradeImportService(OptUserInfo userInfo) : base(userInfo)
{
}
public void ImportFromExcel(Stream streamIn, string TypeName, out int totalNum, out int successNum)
{
totalNum = 0;
successNum = 0;
var rowIndex = 0;
try
{
var ds = Office.ExcelHelper.ReadExcelAsDataSet(streamIn, new[] { 0 }, 0);
if (ds.Tables.Count < 1 || ds.Tables[0].Rows.Count < 2)
{
throw new ServiceException("读取导入数据失败:数据为空") { Tag = "111" };
}
var table = ds.Tables[0];
var reader = new DataRowReader(table, 0);
rowIndex = 1;
totalNum = table.Rows.Count - rowIndex;
foreach (var row in table.Rows.Cast<DataRow>().Skip(1))
{
using (var trans = BeginTransaction())
{
rowIndex++;
if (row.ItemArray.All(n => string.IsNullOrWhiteSpace(n?.ToString())))
{
totalNum--;
continue;
}
reader.SetDataRow(row);
switch (TypeName)
{
case "远期交易":
HandleForwardTrade(reader, ForwardTradePriceModel.STANDARD);//标准模式导入
break;
case "远期交易挂钩标的":
HandleForwardTrade(reader, ForwardTradePriceModel.HOOK_PRICE);//挂钩标的模式导入
break;
default:
HandleFinishForwardTrade(reader);//批量了结导入
break;
}
successNum++;
trans.Commit();
}
}
}
catch (ServiceException se)
{
if (se.Tag != null)
{
throw;
}
throw new ServiceException($"已成功导入{successNum}条;\n第{rowIndex}行,{se.Message}");
}
catch (Exception ex)
{
LogFactory.GetLogger(TypeName).Error(ex);
throw new ServiceException($"已成功导入{successNum}条,\n第{rowIndex}行,发生错误:{ex.Message}", ex);
}
}
#region 远期交易导入
/// <summary>
/// 处理每行数据
/// </summary>
/// <param name="reader"></param>
public void HandleForwardTrade(DataRowReader reader, ForwardTradePriceModel priceModel)
{
OtcTradeForward td = new OtcTradeForward();
td = MapForwardTrade(reader, priceModel);
var otcOptionTradeFullEx = new OtcOptionTradeFullEx { ClientName = td.ClientName };
new OtcOptionSaveChecker(this).CheckAssetBook(td).CheckTrader(td).CheckClient(otcOptionTradeFullEx);
td.ClientId = otcOptionTradeFullEx.ClientId;
CalculatedForwardFieldValue(td, reader);
td.TradeType = "远期";
var mapTd = TradeConverter.ConvertForward(td);
new TradeSaveService(OptUser).SaveTrade(mapTd, TradeSourceEnum.导入交易);
}
public OtcTradeForward MapForwardTrade(DataRowReader reader, ForwardTradePriceModel priceModel)
{
var td = new OtcTradeForward
{
TradeNumber = reader.GetString("交易编号", false),
AssetBookName = reader.GetString("簿记账户名称", true),
TraderName = reader.GetString("交易员名称", true),
ClientName = reader.GetString("交易对手方名称", true),
StructureType = reader.GetString("结构类型", true),
//UnderlyingCode = reader.GetString("标的代码", true),
//BasisUnderlyingCode = reader.GetString("挂钩标的代码", false),
//BasisGap = reader.GetDouble("基差", false),
BuySell = reader.GetString("交易方向", true),
OptionType = reader.GetString("多空方向", false),
TradeAmount = reader.GetDouble("成交数量", false) ?? 0,
Lots = reader.GetDouble("手数", false),
Strike = reader.GetDouble("交割价格", true),
//SpotPrice = reader.GetDouble("期初标的价格", true) ?? 0,
AnnualMarginRate = reader.GetPercent("年化预付金成本", false) ?? 0,
AnnualStoragePrice = reader.GetDouble("年化仓储成本", false) ?? 0,
NoRiskRate = reader.GetPercent("无风险利率", false) ?? 0,
MarginTemplateName = reader.GetString("预付金模板", false),
TradeDate = reader.GetDate("成交日期", true),
ExerciseDate = reader.GetDate("到期日期", true),
SettlementDate = reader.GetDate("结算日期", true),
ObservationDates = reader.GetString("均价结算日", false),
Comments = reader.GetString("备注", false)
};
string IsSupplyForwardValue = reader.GetString("是否补偿远期价值", true);
if (IsSupplyForwardValue == "补偿" || IsSupplyForwardValue == "是")
{
td.MetaDic.Add("IsSupplyForwardValue", "1");
}
else if (IsSupplyForwardValue == "支付")
{
td.MetaDic.Add("IsSupplyForwardValue", "-1");
}
else if (IsSupplyForwardValue == "否")
{
td.MetaDic.Add("IsSupplyForwardValue", "0");
}
else
{
//添加拓展字段 是否补充远期价值,Type2:默认值 -1,其他默认值 0
if (PS.Config.ErpElement.ForwardValueIsSupplyOrPay == YLErp.Configuration.Enums.ForwardValueIsSupplyOrPay.Type2)
{
td.MetaDic.Add("IsSupplyForwardValue", "-1");
}
else
{
td.MetaDic.Add("IsSupplyForwardValue", "0");
}
}
if (priceModel == ForwardTradePriceModel.STANDARD)
{
td.UnderlyingCode = reader.GetString("标的1代码", true);
//判断是否组合标的
var synthetic = DataCacheProvider.GetUnderlyingDataSource().GetSyntheticUnderlying(td.UnderlyingCode);
if (synthetic != null)
{
var model = synthetic.GetSyntheticPriceModel();
var basisUnderlyingCode = reader.GetString("标的2代码", false);
var basisUnderlyingPrice = reader.GetString("标的2期初价格", false);
if (!string.IsNullOrEmpty(basisUnderlyingCode) || !string.IsNullOrEmpty(basisUnderlyingPrice))
{
throw new ServiceException("[组合标的]标的2代码必须为空");
}
var codeSet = synthetic.GetUnderlyingCodes().ToHashSet(StringComparer.OrdinalIgnoreCase);
double SpotPrice = 0;
List<string> spList = new List<string>();
for (var i = 1; i <= 4; i++)
{
var code = reader.GetString("组合标的" + i + "代码", false);
if (string.IsNullOrWhiteSpace(code))
{
continue;
}
if (!codeSet.Remove(code))
{
throw new ServiceException($"[组合标的]{i}_代码 填写错误,组合标的中不存在此标的:{code}");
}
var curSportprice = reader.GetDouble("组合标的" + i + "期初价格", true).Value;
var curUC = model.SuList.FirstOrDefault(n => n.UnderlyingCode == code);
if (curUC != null)
{
curUC.Price = curSportprice;
SpotPrice += curUC.Price * curUC.Coefficient;
}
}
if (codeSet.Any())
{
throw new ServiceException("[组合标的]未填写完整");
}
spList.Add(SpotPrice.OtcFormatUmPrice());
td.SpotPrice = SpotPrice;
td.MetaDic["期初信息"] = spList.ToJson();
td.MetaDic["组合标的"] = model.ToJson();
}
else
{
double SpotPrice = reader.GetDouble("标的1期初价格", true) ?? 0;
td.BasisUnderlyingCode = reader.GetString("标的2代码", false);
double? SpotPrice2 = reader.GetDouble("标的2期初价格", false);
//string[] sp = new string[] { SpotPrice.OtcFormatUmPrice(), SpotPrice2 };
List<string> spList = new List<string>();
spList.Add(SpotPrice.ToString("0.####"));
if (!string.IsNullOrEmpty(td.BasisUnderlyingCode))
{
if (SpotPrice2 == null)
{
throw new ServiceException("填写标的2代码,则必须填写标的2期初价格");
}
else
{
spList.Add((SpotPrice2 ?? 0).ToString("0.####"));
}
}
td.SpotPrice = (double)((decimal)SpotPrice - (decimal)(SpotPrice2 ?? 0));
td.MetaDic["期初信息"] = spList.ToJson();
}
}
else
{
td.UnderlyingCode = reader.GetString("标的代码", true);
td.BasisUnderlyingCode = reader.GetString("挂钩标的代码", false);
td.BasisGap = reader.GetDouble("基差", false);
GetSpotPrice(td);
}
//var um = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
if (PS.Config.Is浙期)
{
var flag = false;
var codes = new List<string>();
codes.Add(td.UnderlyingCode);
codes.Add(td.BasisUnderlyingCode);
//判断标的是否为现货
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");
}
}
//DateTime.TryParse(dateStr, out var date);
switch (td.BuySell)
{
case "Buy":
td.BuySell = "买入";
break;
case "Sell":
td.BuySell = "卖出";
break;
case "买入":
case "卖出":
break;
default:
throw new ServiceException("交易方向 填写错误:" + td.BuySell);
}
td.OptionType = GetOptionType(td.OptionType, td.BuySell);
if (string.IsNullOrEmpty(td.MarginTemplateName))
{
td.MarginTemplateName = "系统默认";
td.MarginRate = 0;
td.PositionMarginRate = 0;
}
else
{
var marginTemplateList = GetMarginTemplateItems();
if (marginTemplateList.Any(a => a.Name.Equals(td.MarginTemplateName)))
{
switch (td.MarginTemplateName)
{
case "系统默认":
td.MarginType = MarginTypeEnum.DEFAULT;
td.MarginRate = 0;
td.PositionMarginRate = 0;
break;
case "无预付金":
td.MarginType = MarginTypeEnum.NONE;
td.MarginRate = 0;
td.PositionMarginRate = 0;
break;
default:
break;
}
var MarginRate = reader.GetDouble("初始预付金率", false);
var PositionMarginRate = reader.GetDouble("持仓预付金率", false);
td.MarginRate = MarginRate ?? 0;
td.PositionMarginRate = PositionMarginRate ?? 0;
var marginTemplate = marginTemplateList.Where(a => a.Name.Equals(td.MarginTemplateName)).FirstOrDefault();
td.MarginType = (MarginTypeEnum)marginTemplate.MarginType;
if (MarginRate == null)
{
td.MarginRate = marginTemplate.InitialMarginRatio ?? 0;
}
if (PositionMarginRate == null)
{
td.PositionMarginRate = marginTemplate.PositionMarginRatio ?? 0;
}
}
else
{
throw new ServiceException("预付金模板填写错误:" + td.MarginTemplateName);
}
}
if (QdpCalendarHelper.IsHoliday((DateTime)td.TradeDate))
{
throw new ServiceException("成交日期:" + td.TradeDate + ",不能为节假日");
}
if (QdpCalendarHelper.IsHoliday((DateTime)td.ExerciseDate))
{
throw new ServiceException("到期日期:" + td.ExerciseDate + ",不能为节假日");
}
if (QdpCalendarHelper.IsHoliday((DateTime)td.SettlementDate))
{
throw new ServiceException("结算日期:" + td.SettlementDate + ",不能为节假日");
}
if (td.TradeDate > td.ExerciseDate)
{
throw new ServiceException("交易日应该在到期日之前");
}
if (td.SettlementDate < td.ExerciseDate)
{
throw new ServiceException("结算日期不能小于到期日期");
}
if (!string.IsNullOrEmpty(td.ObservationDates))
{
DateTime dt = new DateTime();
if (td.ObservationDates.Contains(','))
{
string[] arrayDate = td.ObservationDates.Split(',');
if (!arrayDate.Any(a => DateTime.TryParse(a, out dt)))
throw new ServiceException("均价结算日日期格式填写错误" + td.ObservationDates);
}
else
{
if (!DateTime.TryParse(td.ObservationDates, out dt))
throw new ServiceException("均价结算日日期格式填写错误" + td.ObservationDates);
}
}
#region 观察频率写入metadic表中
string termStr = null;
var ruleStr = reader.GetString("观察周期", false);
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
return td;
}
public string GetOptionType(string OptionType, string BuySell = "")
{
switch (OptionType)
{
case "多头":
case "Call":
return "看涨";
case "空头":
case "Put":
return "看跌";
case "看涨":
case "看跌":
return OptionType;
case "":
case null:
return BuySell == "买入" ? "看涨" : "看跌";
default:
throw new ServiceException("多空方向 填写错误:" + OptionType);
}
}
/// <summary>
/// 计算远期字段值
/// </summary>
/// <param name="td"></param>
/// <returns></returns>
public void CalculatedForwardFieldValue(OtcTradeForward td, DataRowReader reader)
{
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
if (um == null)
{
throw new ServiceException("系统中不存在,导入的标的1代码");
}
else if (!string.IsNullOrEmpty(td.BasisUnderlyingCode))
{
if (DataCacheProvider.GetUnderlyingDataSource().GetData(td.BasisUnderlyingCode) == null)
{
throw new ServiceException("系统中不存在,导入的标的2代码");
}
}
//GetSpotPrice(td);
GetCountRatio(td);
GetNotional_TradeAmount_Lots(td, um);
GetForwardValue(td);
GetOpenCommission_TradePrice(td, reader, null, null);
}
/// <summary>
/// 获取期初价格
/// </summary>
/// <param name="td"></param>
public void GetSpotPrice(OtcTradeForward td)
{
//计算期初价格 期初价格 = 挂钩标的价格 + 基差
if (!string.IsNullOrWhiteSpace(td.BasisUnderlyingCode))
{
var umBasis = DataCacheProvider.GetUnderlyingDataSource().GetData(td.BasisUnderlyingCode);
td.SpotPrice = umBasis.Price + (td.BasisGap ?? 0);
}
else
{
var umBasis = DataCacheProvider.GetUnderlyingDataSource().GetData(td.BasisUnderlyingCode);
td.SpotPrice = umBasis.Price;
}
}
public void GetCountRatio(OtcTradeForward td)
{
var CountRatio = td.CountRatio ?? 0;
if (CountRatio < 1)
{
CountRatio = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode)?.CountRatio ?? 1;
}
td.CountRatio = CountRatio;
}
/// <summary>
/// 获取份额,成交数量,手数
/// </summary>
/// <param name="td"></param>
/// <param name="um"></param>
public void GetNotional_TradeAmount_Lots(OtcTradeForward td, underlying_manager um)
{
if (td.Lots < 0)
throw new ServiceException("手数不能为负数");
if (td.TradeAmount < 0)
throw new ServiceException("成交数量不能为负数");
if (td.TradeAmount == 0 && td.Lots == 0)
throw new ServiceException("成交数量与手数,两者必须填写一个");
if (td.Lots > 0)
{
td.Notional = (double)td.Lots * um.ContractSize;
td.TradeAmount = td.Notional / (double)td.CountRatio;
}
else if (td.TradeAmount > 0)
{
td.Notional = td.TradeAmount * (double)td.CountRatio;
td.Lots = td.Notional / um.ContractSize;
}
td.OriginalNotional = td.Notional;
}
/// <summary>
/// 获取远期价值
/// (交割价格- 期初价格) * 成交数量 * CountRatio *(多-1,空1]*(买入1,卖出 - 1)
/// </summary>
/// <param name="td"></param>
public void GetForwardValue(OtcTradeForward td)
{
var OptionType = GetOptionType(td.OptionType, td.BuySell);
var ForwardValue = (td.Strike - td.SpotPrice) * td.TradeAmount * td.CountRatio * (OptionType == "看涨" ? -1 : 1) * (td.BuySell == "买入" ? 1 : -1);
td.ForwardValue = ForwardValue ?? 0;
}
/// <summary>
/// 获取远期价值
/// </summary>
/// <param name="Strike"></param>
/// <param name="SpotPrice"></param>
/// <param name="TradeAmount"></param>
/// <param name="CountRatio"></param>
/// <param name="OptionType"></param>
/// <param name="BuySell"></param>
/// <returns></returns>
public double GetForwardValue(double Strike, double SpotPrice, double TradeAmount, int CountRatio, string OptionType, string BuySell)
{
OptionType = GetOptionType(OptionType, BuySell);
return (Strike - SpotPrice) * TradeAmount * CountRatio * (OptionType == "看涨" ? -1 : 1) * (BuySell == "买入" ? 1 : -1);
}
/// <summary>
/// 获取远期价值
/// </summary>
/// <param name="Strike"></param>
/// <param name="SpotPrice"></param>
/// <param name="TradeAmount"></param>
/// <param name="CountRatio"></param>
/// <param name="OptionType"></param>
/// <param name="BuySell"></param>
/// <returns></returns>
public double GetForwardValue(double Strike, double SpotPrice, double OriginalNotional, string OptionType, string BuySell)
{
OptionType = GetOptionType(OptionType, BuySell);
return (Strike - SpotPrice) * OriginalNotional * (OptionType == "看涨" ? -1 : 1) * (BuySell == "买入" ? 1 : -1);
}
/// <summary>
/// 获取开仓费用,开仓总费用
/// </summary>
/// <param name="td"></param>
public void GetOpenCommission_TradePrice(OtcTradeForward td, DataRowReader reader, double? OpenCommission, double? TradePrice)
{
if (reader != null)
{
OpenCommission = reader.GetDouble("开仓费用", false);
TradePrice = reader.GetDouble("开仓总费用", false);
}
if (OpenCommission == null && TradePrice == null)
{
throw new ServiceException("开仓费用与开仓总费用,两者必须填写一个");
}
var supplyPrice = td.MetaDic["IsSupplyForwardValue"] == "1" ? td.ForwardValue : td.MetaDic["IsSupplyForwardValue"] == "-1" ? -td.ForwardValue : 0;
//补偿远期价值+开仓费用
if (OpenCommission != null && TradePrice == null)
{
td.TradePrice = supplyPrice + OpenCommission * td.Lots;
td.OpenCommission = OpenCommission.Value;
}
//开仓费用 = (开仓总费用 -(补充远期价值))/ 手数
else if ((OpenCommission != null && TradePrice != null) || (OpenCommission == null && TradePrice != null))
{
td.TradePrice = TradePrice;
td.OpenCommission = ((td.TradePrice - supplyPrice) / td.Lots) ?? 0;
}
}
#endregion
#region 远期交易批量了结导入
public void HandleFinishForwardTrade(DataRowReader reader)
{
TradeCashImportReq tcReq = MapFinishForward(reader);
var td = DbContext.trade.FirstOrDefault(t => t.TradeNumber == tcReq.TradeNumber && t.ValidState != "InValid");
if (td == null)
{
throw new ServiceException("交易数据 不存在,交易编号:" + tcReq.TradeNumber);
}
if (td.TradeStatus != ConsTrade.确认成交)
{
throw new ServiceException("只有交易状态为‘确认成交’,才能进行批量了结导入");
}
td.trade_cash = DbContext.trade_cash.FirstOrDefault(t => t.TradeId == td.id && t.Action == "系统操作-期权费" && t.ValidState != "InValid" && t.IsDeleted == false);
var otcTradeForward = new TradeForwardService(OptUser).GetDetail(td.id);
if ((tcReq.UnwindTradeAmount ?? 0) == 0 && tcReq.UnwindType == "部分平仓")
{
throw new ServiceException("平仓数量不能为0或空值");
}
if (tcReq.UnwindTradeAmount > td.TradeAmount)
{
throw new ServiceException("平仓数量不能大于持仓数量");
}
else if (tcReq.UnwindTradeAmount < td.TradeAmount && tcReq.UnwindType == "全部平仓")
{
throw new ServiceException("全部平仓时,平仓数量等于持仓数量");
}
if (tcReq.UnwindPriceCheck == null && tcReq.UnwindFee == null)
{
throw new ServiceException("当每手平仓费用未填,则平仓总费用必填");
}
CheckValueDate(td, tcReq.ValueDate);
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
var CountRatio = td.CountRatio ?? 0;
if (CountRatio < 1)
{
CountRatio = um?.CountRatio ?? 1;
}
td.CountRatio = CountRatio;
var eodpriceProvider = new YLErp.Modules.DataProviderModule.EodPriceProvider((DateTime)tcReq.ValueDate);
if (tcReq.FinalPrice == null)
{
tcReq.FinalPrice = eodpriceProvider.GetPrice(td.UnderlyingCode, SettlementTypeEnum.ClosePrice);//平仓当天标的价格;
}
if (tcReq.UnwindTradeAmount == td.TradeAmount && tcReq.UnwindType == "部分平仓")
{
tcReq.UnwindType = "全部平仓";
}
if (tcReq.UnwindType == "全部平仓")
{
tcReq.UnwindTradeAmount = td.TradeAmount;
}
var unwindNotional = tcReq.UnwindTradeAmount * td.CountRatio;
double extraAmount = ComputeExtraAmount(td, tcReq) ?? 0;
tcReq.UnwindForwardValue = GetForwardValue(otcTradeForward.Strike ?? 0, tcReq.FinalPrice ?? 0, tcReq.UnwindTradeAmount ?? 0, td.CountRatio ?? 1, td.OptionType, td.BuySell);
tcReq.UnwindRatio = (unwindNotional ?? 0) / (td.OriginalNotional ?? 0);
var supplyPrice = otcTradeForward.MetaDic["IsSupplyForwardValue"] == "1" ? otcTradeForward.ForwardValue : otcTradeForward.MetaDic["IsSupplyForwardValue"] == "-1" ? -otcTradeForward.ForwardValue : 0;
if (tcReq.UnwindFee == null)
{
tcReq.UnwindPriceCheck = tcReq.UnwindPriceCheck ?? 0;
//平仓的总费用 =远期收益+每手平仓费用×平仓手数-(开仓时补偿的远期价值)×平仓数量/成交数量+预付金成本
//其中开仓时补偿的远期价值 = 持仓价值(期初)*Flag
var unwindPrice = (tcReq.UnwindPriceCheck * td.Lots * tcReq.UnwindRatio) ?? 0;
tcReq.UnwindFee = tcReq.UnwindForwardValue + unwindPrice - supplyPrice * tcReq.UnwindRatio + extraAmount;
}
else
{
tcReq.UnwindFee = tcReq.UnwindFee ?? 0;
//平仓费用 = (平仓的总费用 +(开仓时补偿的远期价值* 平仓比例)- 远期收益 - 预付金成本)/ (平仓比例 *手数)
tcReq.UnwindPriceCheck = (tcReq.UnwindFee + supplyPrice * tcReq.UnwindRatio - tcReq.UnwindForwardValue - extraAmount) / (otcTradeForward.Lots * tcReq.UnwindRatio);
}
TradeCashReq req = new TradeCashReq();
req.ValidState = "Valid";
req.UnwindFee = tcReq.UnwindFee ?? 0;
req.Notional = td.Notional;
req.TradeAmount = td.TradeAmount;
req.UnwindPrice = tcReq.UnwindPriceCheck;
req.FinalPrice = tcReq.FinalPrice;
req.UnwindType = tcReq.UnwindType;
req.UnwindNotional = (tcReq.UnwindTradeAmount * td.CountRatio) ?? 0;
req.UnwindPercentRate = td.OriginalNotional > 0 ? (req.UnwindNotional / td.OriginalNotional) ?? 0 : 0;
req.UnwindPricePercentRate = TradeHelper.GetPremiumRateByTradeSinglePrice(req.UnwindPrice, td.SpotPrice);
req.ExtraAmount = extraAmount;
req.ValueDate = tcReq.ValueDate;
//增加现金交割交易记录
var tc = CloseTrade_TradeCashSave(td, req, false, !false, !false);
new TradeCashService(this).SaveTradeCashDetail(tc);
td.TradeSource = TradeSourceEnum.导入交易.ToString();
td.OptId = UserId;
td.OptName = UserName;
td.OptDate = DateTime.Now;
td.StockEqvNotional -= (double)(td.OriginalStockEqvNotional * tc.UnwindPercentRate);
td.Notional -= (double)(td.OriginalNotional * tc.NotionalPercentRate);
td.TradeAmount = td.Notional / um.CountRatio;
td.UnWindNotional = tc.UnwindNotional;
td.UnWindDate = tc.ValueDate;
if (tc.UnwindType == "全部平仓" || (((decimal)(td.OriginalNotional ?? 0) - (decimal)req.UnwindNotional) == 0 && tc.UnwindType == "部分平仓"))
{
td.TradeStatus = ConsTrade.已平仓;
tc.IsLastAction = true;
}
else
{
td.TradeStatus = ConsTrade.确认成交;
td.HasPartialUnWind = 1;
tc.IsLastAction = false;
}
DbContext.SaveChanges();
//增加出入金记录
var ee = new ClientCashinCashoutBLL(this).CloseTrade_ClientCashInCashOutSave(td, tc, tc.ValueDate);
//删除E/Bod数据
RemoveEodTradeAndFutureInfo(false, td.id, tc.ValueDate);
AddTradeAuditLog(td.id);
}
public TradeCashImportReq MapFinishForward(DataRowReader reader)
{
var tc = new TradeCashImportReq
{
TradeNumber = reader.GetString("交易编号", true),
UnwindType = reader.GetString("平仓类型", true),
UnwindTradeAmount = reader.GetDouble("平仓数量", false),
ValueDate = (DateTime)reader.GetDate("平仓日期", true),
FinalPrice = reader.GetDouble("标的价格", false),
UnwindPriceCheck = reader.GetDouble("每手平仓费用", false),
UnwindFee = reader.GetDouble("平仓总费用", false)
};
if (QdpCalendarHelper.IsHoliday((DateTime)tc.ValueDate))
{
throw new ServiceException("平仓日期:" + tc.ValueDate + ",不能为节假日");
}
return tc;
}
/// <summary>
/// 验证平仓日期
/// </summary>
/// <param name="td"></param>
/// <param name="ValueDate"></param>
/// <exception cref="ServiceException"></exception>
public void CheckValueDate(trade td, DateTime ValueDate)
{
if (td.TradeDate > ValueDate)
{
throw new ServiceException("平仓日期必须要大于或等于成交日期");
}
if (ValueDate > td.ExerciseDate)
{
throw new ServiceException("平仓日期必须要小于或等于到期日期");
}
if (ValueDate > valuedateBLL.ValueDate)
{
throw new ServiceException("平仓日期必须要小于或等于系统日期");
}
}
/// <summary>
/// 计算预付金成本
/// </summary>
/// <param name="td"></param>
/// <param name="tcReq"></param>
/// <returns></returns>
public double? ComputeExtraAmount(trade td, TradeCashImportReq tcReq)
{
var valueDate = valuedateBLL.ValueDate;
if (valueDate > td.ExerciseDate)
{
valueDate = td.ExerciseDate.Value;
}
var lastMarginRecord = DbContext.eod_forward_margin.Where(f => f.TradeId == td.id && f.ValueDate < SystemValueDate).OrderByDescending(x => x.ValueDate).FirstOrDefault();
if (lastMarginRecord != null)
{
var totaldays = (valuedateBLL.ValueDate.Date - lastMarginRecord.ValueDate.Date).TotalDays;
double HolidayMargin = lastMarginRecord.SettlePrice * lastMarginRecord.MarginRate * lastMarginRecord.AnnualRate * totaldays / 365;
var unwindAmount = tcReq.UnwindTradeAmount;
var holidayMarginTotal = unwindAmount * HolidayMargin;
var lastMargin = (lastMarginRecord.MarginSum - lastMarginRecord.CloseMarginSum) * ((unwindAmount) / lastMarginRecord.Notional) + lastMarginRecord.CloseMarginSum;
return lastMargin + holidayMarginTotal;
}
return 0;
}
/// <summary>
/// 计算 交易员角度的远期价值
/// </summary>
/// <param name="buySell"></param>
/// <param name="pptionType"></param>
/// <param name="strike"></param>
/// <param name="FinalPrice"></param>
/// <param name="unwindNotional"></param>
/// <returns></returns>
public double ComputForwardValue(string buySell, string optionType, double strike, double FinalPrice, double unwindNotional)
{
//(行权价-标的价格)* 平仓份额
decimal ForwardValue = 0;
if ((buySell == "卖出" && optionType == "看跌") || (buySell == "买入" && optionType == "看涨"))
{
ForwardValue = ((decimal)strike - (decimal)FinalPrice) * (decimal)unwindNotional;
}
else if ((buySell == "卖出" && optionType == "看涨") || (buySell == "买入" && optionType == "看跌"))
{
ForwardValue = -(((decimal)strike - (decimal)FinalPrice) * (decimal)unwindNotional);
}
return (double)ForwardValue;
}
public void AddTradeAuditLog(int TradeId)
{
var auditLog = new TradeAuditLog
{
TradeId = TradeId,
Changes = null,
DataType = "00",
OptType = "批量了结-平仓",
OptId = UserId,
OptName = UserName,
OptDate = OptDate,
AuditFlag = TradeAuditFlag.operation
};
//记录审核日志
DbContext.TradeAuditLog.Add(auditLog);
DbContext.SaveChanges();
}
public List<margin_template> GetMarginTemplateItems()
{
var marginTemplates = DbContext.margin_template.ToList();
List<margin_template> strList = new List<margin_template>();
strList = marginTemplates;
strList.Add(new margin_template
{
Name = "系统默认",
MarginType = (int)MarginTypeEnum.DEFAULT,
InitialMarginRatio = 0,
PositionMarginRatio = 0
});
strList.Add(new margin_template
{
Name = "无预付金",
MarginType = (int)MarginTypeEnum.NONE,
InitialMarginRatio = 0,
PositionMarginRatio = 0
});
return strList;
}
#endregion
}
}