从山证v2.3.0拷贝
This commit is contained in:
@@ -0,0 +1,417 @@
|
||||
using Newtonsoft.Json;
|
||||
using System.Data;
|
||||
using System.Linq.Expressions;
|
||||
using YLErp.Commons;
|
||||
using YLErp.DBModels.Converts;
|
||||
using YLErp.Models.Tag;
|
||||
using YLErp.Modules.TagModule;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.ForwardModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 远期多次了结查询服务
|
||||
/// </summary>
|
||||
public class ForwardMultiCloseService : YLBaseService
|
||||
{
|
||||
public ForwardMultiCloseService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取分页数据(远期)
|
||||
/// </summary>
|
||||
public IPagedList<TradeForwardMultiCloseResultModel> GetPagedDatas(TradeMultiCloseQueryModel queryModel)
|
||||
{
|
||||
if (queryModel is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(queryModel));
|
||||
}
|
||||
|
||||
var tradPredicate = BuildPredicate(queryModel);
|
||||
var basicQuery = from t in DbContext.trade.Where(tradPredicate)
|
||||
select t;
|
||||
var tradCashPredicate = PredicateBuilder.Create<trade_cash>(tc => tc.ValidState != "InValid" && !tc.IsDeleted
|
||||
&& (tc.Action == "系统操作-行权费" || tc.Action == "系统操作-平仓费"));
|
||||
if (queryModel.UnwindDateStart != null)
|
||||
{
|
||||
tradCashPredicate = tradCashPredicate.And(n => n.ValueDate >= queryModel.UnwindDateStart.Value);
|
||||
}
|
||||
if (queryModel.UnwindDateEnd != null)
|
||||
{
|
||||
tradCashPredicate = tradCashPredicate.And(n => n.ValueDate <= queryModel.UnwindDateEnd.Value);
|
||||
}
|
||||
var query = from t in basicQuery.Where(tradPredicate)
|
||||
join tc in DbContext.trade_cash.Where(tradCashPredicate) on t.id equals tc.TradeId
|
||||
join ft in DbContext.trade_forward on t.id equals ft.TradeId
|
||||
//join client in DbContext.client on t.ClientId equals client.id
|
||||
where "远期" == t.TradeType && !tc.IsDeleted
|
||||
select new TradeForwardMultiCloseResultModel
|
||||
{
|
||||
id = t.id,
|
||||
TradeNumber = t.TradeNumber,
|
||||
ClientName = t.ClientName,
|
||||
TradeDate = t.TradeDate,
|
||||
ExerciseDate = t.ExerciseDate,
|
||||
BuySell = t.BuySell,
|
||||
TradeType = t.TradeType,
|
||||
OptionType = t.OptionType == "看涨" ? "多头" : "空头",
|
||||
UnderlyingCode = t.UnderlyingCode,
|
||||
SpotPrice = t.SpotPrice,
|
||||
Strike = t.Strike,
|
||||
TradeSinglePrice = t.TradeSinglePrice ?? 0,
|
||||
TradeAmount = t.TradeAmount,
|
||||
CloseDate = tc.ValueDate,
|
||||
StrikePrice = tc.FinalPrice ?? 0,
|
||||
UnwindPrice = tc.UnwindPrice ?? 0,
|
||||
FinalPrice = tc.FinalPrice ?? 0,
|
||||
UnWindNotional = tc.UnwindNotional ?? tc.Notional,
|
||||
OriginalNotional = t.OriginalNotional ?? 0,
|
||||
ClosePnl = tc.Amount,
|
||||
UnwindFee = tc.Amount,
|
||||
CloseType = tc.Action,
|
||||
UnWindTradeAmount = tc.UnwindTradeAmount ?? 0,
|
||||
UnWindCapitalCost = tc.ExtraAmount ?? 0,//了结资金成本(预付金占用)
|
||||
TradePrice = t.TradePrice, //远期开仓总费用
|
||||
ForwardValue = ft.ForwardValue,//远期价值-成交
|
||||
OrderSeq = tc.Action == "系统操作-行权费" ? 2 : 1,
|
||||
TradeCashId = tc.id,
|
||||
StructureType = t.StructureType,
|
||||
Comments = t.Comments
|
||||
};
|
||||
query = query.OrderByDescending(x => x.id).ThenBy(x => x.OrderSeq).ThenBy(x => x.CloseDate).ThenBy(x => x.TradeCashId);
|
||||
var pagedList = query.ToPagedList(queryModel);
|
||||
TradeForwardMultiCloseResultModel preData = null;
|
||||
|
||||
Dictionary<int, List<TagDto>> tradeTagList = null;
|
||||
if (pagedList != null && pagedList.Any())
|
||||
{
|
||||
using (var service = new TagService(OptUser))
|
||||
{
|
||||
tradeTagList = service.GetTagByTradeIds(pagedList.Select(p => p.id).Distinct().ToList());
|
||||
}
|
||||
}
|
||||
if (tradeTagList == null)
|
||||
{
|
||||
tradeTagList = new Dictionary<int, List<TagDto>>();
|
||||
}
|
||||
foreach (var data in pagedList)
|
||||
{
|
||||
var underlying = DataCacheModule.DataCacheManager.GetUnderlyingDataSource().GetData(data.UnderlyingCode);
|
||||
|
||||
if (preData?.id == data.id)
|
||||
{
|
||||
data.CloseSeq = preData.CloseSeq + 1;
|
||||
}
|
||||
preData = data;
|
||||
|
||||
var openFee = data.OriginalNotional > 0 ? (data.UnWindNotional ?? 0) / data.OriginalNotional.Value * (data.TradePrice ?? 0) : 0;
|
||||
data.RealizedPnl = data.ClosePnl + openFee;
|
||||
|
||||
if (data.CloseType == "系统操作-行权费")
|
||||
{
|
||||
data.CloseType = "到期";
|
||||
}
|
||||
else if (data.CloseType == "系统操作-平仓费")
|
||||
{
|
||||
data.CloseType = "终止";
|
||||
}
|
||||
data.TradeCommission = openFee;
|
||||
data.CountRatio = underlying?.CountRatio ?? 1;
|
||||
var buySell = BuySellConvert.GetClientBuySell(data.BuySell);//客户角度 买入卖出
|
||||
data.UnWindForwardValue = new ForwardTradeImportService(OptUser).GetForwardValue(data.Strike ?? 0, data.FinalPrice ?? 0, data.UnWindTradeAmount, data.CountRatio ?? 1, data.OptionType, data.BuySell);
|
||||
data.UnderlyingName = underlying.UnderlyingName;
|
||||
//拼装标签值
|
||||
if (tradeTagList.ContainsKey(data.id))
|
||||
{
|
||||
data.Tags = tradeTagList[data.id];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return pagedList;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 导出远期数据(最多10000行)
|
||||
/// </summary>
|
||||
/// <param name="queryModel"></param>
|
||||
public byte[] ExportExcel2007(TradeMultiCloseQueryModel queryModel)
|
||||
{
|
||||
if (queryModel is null)
|
||||
{
|
||||
queryModel = new TradeMultiCloseQueryModel();
|
||||
}
|
||||
|
||||
queryModel.PageSize = 10000;
|
||||
|
||||
//var mapper = new Mapper { IgnoreNotMapped = true };
|
||||
//mapper.MapClass<TradeForwardMultiCloseResultModel>()
|
||||
// .Map("交易编号", o => o.TradeNumber)
|
||||
// .Map("交易对手方", o => o.ClientName)
|
||||
// .Map("成交日期", o => o.TradeDate)
|
||||
// .Map("到期日期", o => o.ExerciseDate)
|
||||
// .Map("买卖方向", o => o.BuySell)
|
||||
// .Map("结构类型", o => o.TradeType)
|
||||
// .Map("多空方向", o => o.OptionType)
|
||||
// .Map("标的代码", o => o.UnderlyingCode)
|
||||
// .Map("期初标的价格", o => o.SpotPrice)
|
||||
// .Map("执行价格", o => o.Strike)
|
||||
// .Map("远期价值(成交)", o => o.ForwardValue)
|
||||
// .Map("成交数量", o => o.OriginalNotional)
|
||||
// .Map("成交手续费", o => o.TradeCommission)
|
||||
// .Map("了结序号", o => o.CloseSeq)
|
||||
// .Map("了结方式", o => o.CloseType)
|
||||
// .Map("了结日期", o => o.CloseDate)
|
||||
// .Map("了结标的价格", o => o.StrikePrice)
|
||||
// .Map("远期价值(了结)", o => o.UnWindForwardValue)
|
||||
// .Map("了结数量", o => o.UnWindNotional)
|
||||
// .Map("了结手续费", o => o.UnWindCommission)
|
||||
// .Map("了结资金成本", o => o.UnWindCapitalCost)
|
||||
// .Map("了结金额", o => o.UnwindFee)
|
||||
// .Map("实现盈亏", o => o.RealizedPnl)
|
||||
// .Format("yyyy-MM-dd", o => o.TradeDate)
|
||||
// .Format("yyyy-MM-dd", o => o.ExerciseDate)
|
||||
// .Format("yyyy-MM-dd", o => o.CloseDate)
|
||||
// .Format("0.00", o => o.Strike);
|
||||
|
||||
//mapper.ForHeader(cell =>
|
||||
//{
|
||||
// if (cell.ColumnIndex < 2)
|
||||
// {
|
||||
// cell.Sheet.SetColumnWidth(cell.ColumnIndex, 20 * 256);
|
||||
// }
|
||||
// else if (cell.StringCellValue.EndsWith("日期"))
|
||||
// {
|
||||
// cell.Sheet.SetColumnWidth(cell.ColumnIndex, 12 * 256);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// cell.Sheet.SetColumnWidth(cell.ColumnIndex, 10 * 256);
|
||||
// }
|
||||
|
||||
//});
|
||||
|
||||
var pagedData = GetPagedDatas(queryModel);
|
||||
|
||||
Func<DateTime, string> formatValue = (cv) => { return cv.ToString("yyyy-MM-dd"); };
|
||||
|
||||
var dc = new List<ExcelHelper.DataColumnModel>();
|
||||
dc.Add(new ExcelHelper.DataColumnModel("交易编号", "TradeNumber"));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("交易对手方", "ClientName"));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("成交日期", "TradeDate", (cv, obj) => formatValue(((DateTime)cv))));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("到期日期", "ExerciseDate", (cv, obj) => formatValue(((DateTime)cv))));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("买卖方向", "BuySell"));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("结构类型", "TradeType", (cv, obj) =>
|
||||
{//掉期类型展示
|
||||
if (obj is TradeForwardMultiCloseResultModel model)
|
||||
{
|
||||
return model.StructureType ?? cv;
|
||||
}
|
||||
return cv;
|
||||
}
|
||||
));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("多空方向", "OptionType"));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("标的名称", "UnderlyingName"));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("标的代码", "UnderlyingCode"));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("期初标的价格", "SpotPrice", typeof(double)));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("执行价格", "Strike", typeof(double)));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("远期价值(成交)", "ForwardValue", typeof(double)));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("成交数量", "OriginalNotional", typeof(double)));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("成交手续费", "TradeCommission", typeof(double)));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("了结序号", "CloseSeq", typeof(double)));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("了结方式", "CloseType"));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("了结日期", "CloseDate", (cv, obj) => formatValue(((DateTime)cv))));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("了结标的价格", "StrikePrice", typeof(double)));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("远期价值(了结)", "UnWindForwardValue", typeof(double)));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("了结数量", "UnWindNotional", typeof(double)));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("了结手续费", "UnWindCommission", typeof(double)));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("了结资金成本", "UnWindCapitalCost", typeof(double)));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("了结金额", "UnwindFee", typeof(double)));
|
||||
dc.Add(new ExcelHelper.DataColumnModel("实现盈亏", "RealizedPnl", typeof(double)));
|
||||
new ExcelHelper().ListToExcel<TradeForwardMultiCloseResultModel>(dc.ToArray(), pagedData.Items.ToList(), "多次了结", true, out var buffer);
|
||||
return buffer;
|
||||
//using (var stream = new MemoryStream())
|
||||
//{
|
||||
// mapper.Save(stream, pagedData.Items, "多次了结", overwrite: true);
|
||||
// return stream.ToArray();
|
||||
//}
|
||||
}
|
||||
|
||||
private Expression<Func<trade, bool>> BuildPredicate(TradeMultiCloseQueryModel queryModel)
|
||||
{
|
||||
var predicate = PredicateBuilder.Create<trade>(t => t.ValidState != ConsGlobal.InValid);
|
||||
if (queryModel.UserAssets != null || queryModel.UserClients != null)
|
||||
{
|
||||
predicate = predicate.And(n => queryModel.UserAssets.Contains(n.AssetId) || queryModel.UserClients.Contains(n.ClientId));
|
||||
}
|
||||
if (queryModel.TradeDateStart != null)
|
||||
{
|
||||
predicate = predicate.And(n => n.TradeDate >= queryModel.TradeDateStart.Value);
|
||||
}
|
||||
if (queryModel.TradeDateEnd != null)
|
||||
{
|
||||
predicate = predicate.And(n => n.TradeDate <= queryModel.TradeDateEnd.Value);
|
||||
}
|
||||
if (queryModel.ExerciseDateStart != null)
|
||||
{
|
||||
predicate = predicate.And(n => n.ExerciseDate >= queryModel.ExerciseDateStart.Value);
|
||||
}
|
||||
if (queryModel.ExerciseDateEnd != null)
|
||||
{
|
||||
predicate = predicate.And(n => n.ExerciseDate <= queryModel.ExerciseDateEnd.Value);
|
||||
}
|
||||
if (queryModel.AssetUnitIds != null && queryModel.AssetUnitIds.Any(a => a > 0))
|
||||
{
|
||||
predicate = predicate.And(n => queryModel.AssetUnitIds.Contains(n.AssetId));
|
||||
}
|
||||
if (queryModel.ClientIdList.Any())
|
||||
{
|
||||
predicate = predicate.And(n => queryModel.ClientIdList.Contains(n.ClientId));
|
||||
}
|
||||
if (!string.IsNullOrWhiteSpace(queryModel.TradeNumber))
|
||||
{
|
||||
var TradeNumber = queryModel.TradeNumber.Trim();
|
||||
predicate = predicate.And(n => n.TradeNumber.Contains(TradeNumber));
|
||||
}
|
||||
if (queryModel.UnderlyingIdList != null && queryModel.UnderlyingIdList.Any(n => n > 0))
|
||||
{
|
||||
predicate = predicate.And(n => queryModel.UnderlyingIdList.Contains(n.UnderlyingId));
|
||||
}
|
||||
|
||||
if (queryModel.TagIds != null && queryModel.TagIds.Count > 0)
|
||||
{
|
||||
var tradeTagIdQuery = from tt in DbContext.trade_tag
|
||||
where queryModel.TagIds.Contains(tt.TagId)
|
||||
select tt.TradeId;
|
||||
predicate = predicate.And(p => tradeTagIdQuery.Contains(p.id));
|
||||
}
|
||||
|
||||
return predicate;
|
||||
}
|
||||
|
||||
private int GetDirection(string buySell, string callPut)
|
||||
{
|
||||
if ((buySell == "买入" && callPut == "空头")
|
||||
|| (buySell == "卖出" && callPut == "多头"))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else if ((buySell == "买入" && callPut == "多头")
|
||||
|| (buySell == "卖出" && callPut == "空头"))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 多次了结服务结果Model
|
||||
/// </summary>
|
||||
public class TradeForwardMultiCloseResultModel : OtcTradeBase
|
||||
{
|
||||
/// <summary>
|
||||
/// 行权方式
|
||||
/// </summary>
|
||||
public string ExerciseWay { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 了结方式
|
||||
/// </summary>
|
||||
public string CloseType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 了结日期
|
||||
/// </summary>
|
||||
public DateTime? CloseDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 了结标的价格
|
||||
/// </summary>
|
||||
public double StrikePrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 权利金(了结)
|
||||
/// </summary>
|
||||
public double UnwindPrice { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 了结金额
|
||||
/// </summary>
|
||||
public double UnwindFee { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 平仓盈亏
|
||||
/// </summary>
|
||||
public double ClosePnl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 实现盈亏
|
||||
/// </summary>
|
||||
public double RealizedPnl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 排序序号
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public int OrderSeq { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
public int TradeCashId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 了结序号
|
||||
/// </summary>
|
||||
public int CloseSeq { get; set; } = 1;
|
||||
|
||||
/// <summary>
|
||||
/// 远期价值(了结)
|
||||
/// </summary>
|
||||
public double UnWindForwardValue { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 远期价值(成交)
|
||||
/// </summary>
|
||||
public double ForwardValue { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 平仓数量
|
||||
/// </summary>
|
||||
public double UnWindTradeAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 成交手续费(了结部分所占的开仓总费用)
|
||||
/// </summary>
|
||||
public double TradeCommission { get; set; }
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 了结远期价值(远期收益)
|
||||
/// </summary>
|
||||
public double UnWindForwardProfits { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 了结手续费(平仓费用 * 了结数量 / 每手数量)
|
||||
/// </summary>
|
||||
public double UnWindCommission { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 了结资金成本(了结部分的预付金占用成本)
|
||||
/// </summary>
|
||||
public double UnWindCapitalCost { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标的名称
|
||||
/// </summary>
|
||||
public string UnderlyingName { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 交易标签
|
||||
/// </summary>
|
||||
public List<TagDto> Tags { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,896 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,533 @@
|
||||
using BaseOUDAL;
|
||||
using Dapper;
|
||||
using YLErp.BLL;
|
||||
using YLErp.DBModels.Consts;
|
||||
using YLErp.Model;
|
||||
using YLErp.Model.Enum;
|
||||
using YLErp.Modules.SalesModule;
|
||||
using YLErp.Modules.TagModule;
|
||||
using YLErp.Modules.TradeModule.OrderModule;
|
||||
using YLErp.QdpModule;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.ForwardModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 远期交易服务
|
||||
/// </summary>
|
||||
public class TradeForwardService : TradeServiceBase
|
||||
{
|
||||
public TradeForwardService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询trade
|
||||
/// </summary>
|
||||
public SearchListResult<trade> SearchList(TradeReq req, bool isUnionToday = false, bool isExerciseDateReport = false)
|
||||
{
|
||||
var query = CreateTradeQuery(req, isUnionToday, isExerciseDateReport);
|
||||
|
||||
var gsum = new tradeGridSum();
|
||||
|
||||
if (query.Where(x => x.TradeStatus != "已执行" && x.TradeStatus != "已到期" && x.TradeStatus != "已平仓").Any())
|
||||
{
|
||||
gsum.TradeAmountSum = query.Where(x => x.TradeStatus != "已执行" && x.TradeStatus != "已到期" && x.TradeStatus != "已平仓")?.Sum(q => q.TradeAmount);
|
||||
}
|
||||
|
||||
var retListResult = query.ToSearchList(req);
|
||||
|
||||
retListResult.Sum = gsum;
|
||||
//获取销售提成信息
|
||||
foreach (var item in retListResult.rows)
|
||||
{
|
||||
item.SalesCommission = new SalesCommissionDataService(OptUser).GetTradeCommissionInfo(item.id);
|
||||
if (PS.Config.ErpElement.SalesCommissionCalculation == "公式1" && item.SalesCommission?.Commission != null)
|
||||
{
|
||||
item.SalesCommission.Commission = item.SalesCommission.Commission * item.SalesCommission.SalesIds.Count();
|
||||
}
|
||||
item.UnderlyingName = DataCacheModule.DataCacheManager.GetUnderlyingDataSource().GetData(item.UnderlyingCode).UnderlyingName;
|
||||
}
|
||||
|
||||
return retListResult;
|
||||
}
|
||||
|
||||
private IQueryable<trade> CreateTradeQuery(TradeReq req, bool isUnionToday = false, bool isExerciseDateReport = false)
|
||||
{
|
||||
var predicate = PredicateBuilder.Create<trade>(t => t.ValidState != "InValid" && t.TradeType == "远期");
|
||||
if (req.UserAssets != null && req.UserClients != null)
|
||||
{
|
||||
predicate = predicate.And(t => req.UserAssets.Contains(t.AssetId) || req.UserClients.Contains(t.ClientId));
|
||||
}
|
||||
var query = DbContext.trade.Where(predicate);
|
||||
if (!string.IsNullOrEmpty(req.ContractCode))
|
||||
{
|
||||
query = from source in query
|
||||
join tcrConfirm in DbContext.trade_contract_r.Where(aa => aa.Type == ContractTypeEnum.Trade && aa.IsValid) on new { id = source.ParentTradeId > 0 ? source.ParentTradeId : source.id } equals new { id = tcrConfirm.TradeId } into tcrConfirms
|
||||
from tcrConfirm in tcrConfirms.DefaultIfEmpty()
|
||||
where tcrConfirm.ContractCode.Contains(req.ContractCode)
|
||||
select source;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.UnderlyingAssetClass))
|
||||
{
|
||||
query = query.Where(d => d.UnderlyingAssetClass.Contains(req.UnderlyingAssetClass));
|
||||
}
|
||||
|
||||
|
||||
if (!string.IsNullOrEmpty(req.UnderlyingInstrumentTypes))
|
||||
{
|
||||
query = query.Where(d => req.UnderlyingInstrumentTypesList.Contains(d.UnderlyingInstrumentType));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.OptIds))
|
||||
{
|
||||
query = query.Where(d => req.OptIdsList.Contains(d.OptId + ""));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.Comments))
|
||||
{
|
||||
query = query.Where(d => d.Comments.Contains(req.Comments));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.UnderlyingIds))
|
||||
{
|
||||
query = query.Where(d => req.UnderlyingIdsInt.Contains(d.UnderlyingId));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.TradeIds))
|
||||
{
|
||||
query = query.Where(d => req.TradeIdList.Contains(d.id));
|
||||
}
|
||||
|
||||
//获取当日成交的数据
|
||||
//当日成交包括操作日期和交易日为当前系统日期的数据
|
||||
if (req.TabIndex == (int)TradeTabIndexEnum.今日成交)
|
||||
{
|
||||
var optDateStart = valuedateBLL.ValueDate;
|
||||
var optDateEnd = valuedateBLL.ValueDate.AddDays(1);
|
||||
var tradeDateStart = valuedateBLL.ValueDate;
|
||||
var tradeDateEnd = valuedateBLL.ValueDate.AddDays(1);
|
||||
|
||||
query = query.Where(d => (d.TradeDate >= tradeDateStart && d.TradeDate < tradeDateEnd) || (d.OptDate >= optDateStart && d.OptDate < tradeDateEnd));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (req.TradeDateStart != DateTime.MinValue)
|
||||
{
|
||||
query = query.Where(d => d.TradeDate >= req.TradeDateStart);
|
||||
}
|
||||
|
||||
if (req.TradeDateEnd != DateTime.MinValue)
|
||||
{
|
||||
var TradeDateTemp = req.TradeDateEnd.AddDays(1);
|
||||
query = query.Where(d => d.TradeDate < TradeDateTemp);
|
||||
}
|
||||
|
||||
if (req.OptDateStart != DateTime.MinValue)
|
||||
{
|
||||
query = query.Where(d => d.OptDate >= req.OptDateStart);
|
||||
}
|
||||
|
||||
if (req.OptDateEnd != DateTime.MinValue)
|
||||
{
|
||||
var OptDateTemp = req.OptDateEnd.AddDays(1);
|
||||
query = query.Where(d => d.OptDate < OptDateTemp);
|
||||
}
|
||||
}
|
||||
|
||||
//获取当日到期日数据
|
||||
if (req.TabIndex == (int)TradeTabIndexEnum.今日到期)
|
||||
{
|
||||
query = query.Where(d => d.ExerciseDate == valuedateBLL.ValueDate);
|
||||
}
|
||||
//获取明日到期日数据
|
||||
else if (req.TabIndex == (int)TradeTabIndexEnum.明日到期)
|
||||
{
|
||||
var tommorow = QdpCalendarHelper.GetNonHoliday(valuedateBLL.ValueDate.AddDays(1));
|
||||
query = query.Where(d => d.ExerciseDate == tommorow);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (req.ExerciseDateEnd == null)
|
||||
{
|
||||
req.ExerciseDateEnd = DateTime.MaxValue;
|
||||
}
|
||||
|
||||
if (req.ExerciseDateStart == null)
|
||||
{
|
||||
req.ExerciseDateStart = DateTime.MinValue;
|
||||
}
|
||||
|
||||
if (isExerciseDateReport)
|
||||
{
|
||||
query = query.Where(d => d.ExerciseDate >= req.ExerciseDateStart && d.ExerciseDate <= req.ExerciseDateEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
query = query.Where(d => d.ExerciseDate == null || (d.ExerciseDate >= req.ExerciseDateStart && d.ExerciseDate <= req.ExerciseDateEnd));
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.TraderNames))
|
||||
{
|
||||
query = query.Where(d => req.TraderNamesList.Contains(d.TraderId));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.TradeNumber))
|
||||
{
|
||||
query = query.Where(d => d.TradeNumber == req.TradeNumber || d.TradeNumber.Contains(req.TradeNumber));
|
||||
}
|
||||
|
||||
if (req.ClientId != null)
|
||||
{
|
||||
query = query.Where(d => d.ClientId == req.ClientId);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.ClientName))
|
||||
{
|
||||
query = query.Where(d => d.ClientName.Contains(req.ClientName));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.UnderlyingCode))
|
||||
{
|
||||
query = query.Where(d => d.UnderlyingCode.Contains(req.UnderlyingCode));
|
||||
}
|
||||
|
||||
if (req.UnderlyingCodeList != null)
|
||||
{
|
||||
query = query.Where(d => req.UnderlyingCodeList.Contains(d.UnderlyingCode));
|
||||
}
|
||||
|
||||
if (req.UnderlyingId != null)
|
||||
{
|
||||
query = query.Where(d => d.UnderlyingId == req.UnderlyingId);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.BuySell))
|
||||
{
|
||||
query = query.Where(d => d.BuySell.Contains(req.BuySell));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.OptionType))
|
||||
{
|
||||
query = query.Where(d => d.OptionType == req.OptionType);
|
||||
}
|
||||
|
||||
if (req.StartDateStart != DateTime.MinValue)
|
||||
{
|
||||
query = query.Where(d => d.StartDate >= req.StartDateStart);
|
||||
}
|
||||
|
||||
if (req.StartDateEnd != DateTime.MinValue)
|
||||
{
|
||||
var StartDateTemp = req.StartDateEnd.AddDays(1);
|
||||
query = query.Where(d => d.StartDate < StartDateTemp);
|
||||
}
|
||||
|
||||
//过滤已平仓,已到期,已执行数据
|
||||
else if (req.TabIndex == (int)TradeTabIndexEnum.今日到期 || req.TabIndex == (int)TradeTabIndexEnum.明日到期)
|
||||
{
|
||||
query = query.Where(d => d.TradeStatus != ConsTrade.已平仓 && d.TradeStatus != ConsTrade.已到期 && d.TradeStatus != ConsTrade.已执行);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.TradeStatus))
|
||||
{
|
||||
var statuses = req.TradeStatus.Split(',').ToList();
|
||||
query = query.Where(d => statuses.Contains(d.TradeStatus));
|
||||
}
|
||||
|
||||
if (req.TradeStatusList != null)
|
||||
{
|
||||
query = query.Where(d => req.TradeStatusList.Contains(d.TradeStatus));
|
||||
}
|
||||
if (req.AssetIdList.Any())
|
||||
{
|
||||
query = query.Where(d => req.AssetIdList.Contains(d.AssetId));
|
||||
}
|
||||
if (req.ClientIdsInt.Any())
|
||||
{
|
||||
query = query.Where(d => req.ClientIdsInt.Contains(d.ClientId));
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(req.OptName))
|
||||
{
|
||||
query = query.Where(d => d.OptName.Contains(req.OptName));
|
||||
}
|
||||
if (req.TagIds != null && req.TagIds.Count > 0)
|
||||
{
|
||||
var tradeTagIdQuery = from tt in DbContext.trade_tag
|
||||
where req.TagIds.Contains(tt.TagId)
|
||||
select tt.TradeId;
|
||||
query = query.Where(p => tradeTagIdQuery.Contains(p.id));
|
||||
}
|
||||
|
||||
query = query.Where(d => !d.ValidState.Equals("InValid"));
|
||||
|
||||
if (string.IsNullOrEmpty(req.sidx))
|
||||
{
|
||||
req.sidx = "id";
|
||||
req.sord = "desc";
|
||||
}
|
||||
|
||||
if (isUnionToday)
|
||||
{
|
||||
var todaybalanceStatus = new List<string> { "已到期", "已执行", "已平仓" };
|
||||
var curDate = valuedateBLL.ValueDate;
|
||||
//+ trade今天被exercise/expire的option. 排序按照optDate,从新到旧排
|
||||
query = query.Union(from s in DbContext.trade where s.ClientId == req.ClientId && todaybalanceStatus.Contains(s.TradeStatus) && s.OptDate >= curDate select s);
|
||||
}
|
||||
|
||||
query = query.OrderByDescending(s => s.OptDate);
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取数据详情
|
||||
/// </summary>
|
||||
public OtcTradeForward GetDetail(int id)
|
||||
{
|
||||
var tdResult = DbContext.Database.GetDbConnection().Query<OtcTradeForward>("select * from trade where id=" + id).FirstOrDefault();
|
||||
|
||||
if (tdResult == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var forward = DbContext.trade_forward.FirstOrDefault(n => n.TradeId == id);
|
||||
|
||||
if (forward == null)
|
||||
{
|
||||
throw new ServiceException("交易数据损坏,扩展数据未找到");
|
||||
}
|
||||
|
||||
YLAutoMapper.Map(forward, tdResult);
|
||||
|
||||
tdResult.MetaDic = new TradeMetaService(this).GetTradeMeta(tdResult.id);
|
||||
if (!tdResult.MetaDic.ContainsKey("IsSupplyForwardValue"))
|
||||
{
|
||||
if (PS.Config.ErpElement.ForwardValueIsSupplyOrPay == YLErp.Configuration.Enums.ForwardValueIsSupplyOrPay.Type2)
|
||||
{
|
||||
tdResult.MetaDic.Add("IsSupplyForwardValue", "-1");
|
||||
}
|
||||
else
|
||||
{
|
||||
tdResult.MetaDic.Add("IsSupplyForwardValue", "0");
|
||||
}
|
||||
}
|
||||
|
||||
tdResult.VarietyId = UnderlyingDataProvider.GetUnderlying(tdResult.UnderlyingCode)?.UnderlyingTypeId ?? 0;
|
||||
|
||||
var un = UnderlyingDataProvider.GetUnderlying(tdResult.UnderlyingId);
|
||||
if (un != null && un.IsSynthetic() && !tdResult.MetaDic.ContainsKey("组合标的"))
|
||||
{
|
||||
var synthetic = UnderlyingDataProvider.GetSyntheticUnderlying(tdResult.UnderlyingCode);
|
||||
if (synthetic != null)
|
||||
{
|
||||
tdResult.MetaDic["组合标的"] = synthetic.GetSyntheticPriceModel().ToJson();
|
||||
}
|
||||
}
|
||||
|
||||
tdResult.SalesCommission = new SalesCommissionDataService(this).GetTradeCommissionInfo(tdResult.id);
|
||||
|
||||
return tdResult;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除交易
|
||||
/// </summary>
|
||||
public void InValidTrade(int id)
|
||||
{
|
||||
var r = DbContext.trade.Find(id);
|
||||
|
||||
if (r == null)
|
||||
{
|
||||
throw new ServiceException("找不到交易信息");
|
||||
}
|
||||
|
||||
r.ValidState = ConsGlobal.InValid;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(r.TradeNumber))
|
||||
{
|
||||
var contractBll = new TradeContractBLL(UserId, UserName);
|
||||
|
||||
contractBll.DeleteConfirmBook(r.id);
|
||||
|
||||
if (r.TradeNumber.StartsWith("CW"))
|
||||
{
|
||||
r.TradeNumber = r.TradeNumber.Replace("CW", "XX");
|
||||
}
|
||||
else //if (PS.Config.Is光大光子)
|
||||
{
|
||||
r.TradeNumber = r.TradeNumber.Insert(0, "XX");
|
||||
}
|
||||
}
|
||||
|
||||
//设置相关提成失效
|
||||
new SalesCommissionDataService(OptUser).SetCommissionInVaild(r.id);
|
||||
|
||||
RemoveEodTradeAndFutureInfo(false, r.id, DateTime.MinValue);
|
||||
new DealModule.TradeConfirmService(this).EditReportStatus(r.id);
|
||||
AddTradeOperationHistoryAndSetParentTradeInfo(false, r, "删除交易");
|
||||
|
||||
//删除所有trade关联表中数据
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存交易
|
||||
/// </summary>
|
||||
public trade SaveData(OtcTradeForward req)
|
||||
{
|
||||
req.TradeType = "远期";
|
||||
var td = TradeConverter.ConvertForward(req);
|
||||
td = new TradeSaveService(this).SaveTrade(td, TradeSourceEnum.系统交易);
|
||||
var variety = UnderlyingDataProvider.GetVariety(td.UnderlyingCode);
|
||||
if (variety != null)
|
||||
{
|
||||
td.QuoteUnit = variety.QuoteUnit;
|
||||
td.QuoteUnitSingle = variety.QuoteUnitSingle;
|
||||
}
|
||||
using (var tagService = new TagService(OptUser))
|
||||
{
|
||||
tagService.SetTradeTagForTradeEdit(new TagModule.Dto.SetTradeTagForTradeEditRequest
|
||||
{
|
||||
TradeId = td.id,
|
||||
Tags = req.Tags
|
||||
});
|
||||
}
|
||||
return td;
|
||||
}
|
||||
|
||||
public TradeCheckModel GetCheckTrade(int? id)
|
||||
{
|
||||
var service = new TradeMetaService(this);
|
||||
var model = new TradeCheckModel
|
||||
{
|
||||
Trade = DbContext.trade.FirstOrDefault(n => n.id == id)
|
||||
};
|
||||
if (model.Trade == null)
|
||||
{
|
||||
throw new ServiceException("没有找到数据");
|
||||
}
|
||||
var forward = DbContext.trade_forward.FirstOrDefault(t => t.TradeId == model.Trade.id);
|
||||
if (forward == null)
|
||||
{
|
||||
throw new ServiceException("没有找到远期数据");
|
||||
}
|
||||
|
||||
model.Trade.trade_forward = forward;
|
||||
|
||||
model.UnderlyingInfo = UnderlyingDataProvider.GetUnderlying(model.Trade.UnderlyingCode);
|
||||
|
||||
var tradeCheck = DbContext.trade_check.FirstOrDefault(t => t.TradeId == model.Trade.id && t.ValidState != "InValid");
|
||||
if (tradeCheck != null)
|
||||
{
|
||||
model.diffList = TradeCheckUtil.GetDiffs(model.Trade, tradeCheck.TradeModel);
|
||||
|
||||
model.Trade.ExerciseDate = tradeCheck.TradeModel.ExerciseDate;
|
||||
model.Trade.TradeDate = tradeCheck.TradeModel.TradeDate;
|
||||
model.Trade.SettlementDate = tradeCheck.TradeModel.SettlementDate;
|
||||
model.Trade.Strike = tradeCheck.TradeModel.Strike;
|
||||
model.Trade.TradeAmount = tradeCheck.TradeModel.TradeAmount;
|
||||
model.Trade.TradeSinglePrice = tradeCheck.TradeModel.TradeSinglePrice;
|
||||
model.Trade.TradeDate = tradeCheck.TradeModel.TradeDate;
|
||||
model.Trade.SpotPrice = tradeCheck.TradeModel.SpotPrice;
|
||||
model.Trade.StockEqvNotional = tradeCheck.TradeModel.StockEqvNotional;
|
||||
model.Trade.TradeOpenVolatility = tradeCheck.TradeModel.TradeOpenVolatility;
|
||||
model.Trade.TradeCloseVolatility = tradeCheck.TradeModel.TradeCloseVolatility;
|
||||
model.Trade.NumOfSmoothingDays = tradeCheck.TradeModel.NumOfSmoothingDays;
|
||||
model.Trade.TradePrice = tradeCheck.TradeModel.TradePrice;
|
||||
model.Trade.BuySell = tradeCheck.TradeModel.BuySell;
|
||||
model.Trade.ExerciseMode = tradeCheck.TradeModel.ExerciseMode;
|
||||
model.Trade.OptionType = tradeCheck.TradeModel.OptionType;
|
||||
model.Trade.SettlementType = tradeCheck.TradeModel.SettlementType;
|
||||
model.Trade.Lots = tradeCheck.TradeModel.Lots;
|
||||
model.Trade.SalesCommission = new SalesCommissionDataService(OptUser).GetTradeCommissionInfo(model.Trade.id);
|
||||
if (PS.Config.ErpElement.SalesCommissionCalculation == "公式1")
|
||||
{//计提法只支持百分比;
|
||||
if (model.Trade.SalesCommission.Commission.Normalize() == 0)
|
||||
{
|
||||
model.Trade.SalesCommission.Commission = 1;
|
||||
model.Trade.SalesCommission.CommissionFixed = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
model.Trade.SalesCommission.Commission = model.Trade.SalesCommission.Commission * model.Trade.SalesCommission.SalesIds.Count();
|
||||
}
|
||||
}
|
||||
model.Trade.NoRiskRate = tradeCheck.TradeModel.NoRiskRate;
|
||||
model.Trade.trade_forward = tradeCheck.TradeModel.trade_forward;
|
||||
model.Trade.MetaDic = service.GetTradeMeta(model.Trade.id);
|
||||
if (model.Trade.MetaDic.ContainsKey("ActualExerciseDate") && DateTime.TryParse(model.Trade.MetaDic["ActualExerciseDate"],out DateTime ActualExerciseDate))
|
||||
{
|
||||
model.Trade.ActualExerciseDate = ActualExerciseDate;
|
||||
}
|
||||
return model;
|
||||
}
|
||||
|
||||
model.Trade.ExerciseDate = null;
|
||||
model.Trade.Strike = null;
|
||||
model.Trade.TradeAmount = 0;
|
||||
model.Trade.TradeSinglePrice = null;
|
||||
model.Trade.TradeDate = null;
|
||||
model.Trade.SpotPrice = null;
|
||||
model.Trade.StockEqvNotional = 0;
|
||||
model.Trade.TradeOpenVolatility = null;
|
||||
model.Trade.TradeCloseVolatility = null;
|
||||
model.Trade.NumOfSmoothingDays = null;
|
||||
model.Trade.TradePrice = null;
|
||||
model.Trade.BuySell = null;
|
||||
model.Trade.ExerciseMode = null;
|
||||
model.Trade.OptionType = null;
|
||||
model.Trade.SettlementType = 0;
|
||||
model.Trade.Lots = null;
|
||||
model.Trade.SalesCommission = new SalesCommissionDataService(OptUser).GetTradeCommissionInfo(model.Trade.id);
|
||||
if (PS.Config.ErpElement.SalesCommissionCalculation == "公式1")
|
||||
{//计提法只支持百分比;
|
||||
if (model.Trade.SalesCommission.Commission.Normalize() == 0)
|
||||
{
|
||||
model.Trade.SalesCommission.Commission = 1;
|
||||
model.Trade.SalesCommission.CommissionFixed = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
model.Trade.SalesCommission.Commission = model.Trade.SalesCommission.Commission * model.Trade.SalesCommission.SalesIds.Count();
|
||||
}
|
||||
}
|
||||
//将无风险利率和年华预付金利率数值从小数转换百分数
|
||||
model.Trade.NoRiskRate *= 100;
|
||||
forward.AnnualMarginRate *= 100;
|
||||
forward.OpenCommission = 0;
|
||||
model.Trade.trade_forward = forward;
|
||||
model.Trade.MetaDic = service.GetTradeMeta(model.Trade.id);
|
||||
|
||||
if (model.Trade.MetaDic.ContainsKey("ActualExerciseDate") && DateTime.TryParse(model.Trade.MetaDic["ActualExerciseDate"], out DateTime newActualExerciseDate))
|
||||
{
|
||||
model.Trade.ActualExerciseDate = newActualExerciseDate;
|
||||
}
|
||||
|
||||
return model;
|
||||
}
|
||||
}
|
||||
|
||||
public class TradeCheckModel
|
||||
{
|
||||
/// <summary>
|
||||
/// 交易信息
|
||||
/// </summary>
|
||||
public trade Trade { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 标的信息
|
||||
/// </summary>
|
||||
public underlying_manager UnderlyingInfo { get; set; }
|
||||
|
||||
public HashSet<string> diffList { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否显示初始预付金
|
||||
/// </summary>
|
||||
public bool ShowInitialMargin => valuedateBLL.SystemDate.CanSetInitialMargin;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
using YLErp.BLL;
|
||||
using YLErp.DBModels.Converts;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.ForwardModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 远期交易平仓服务
|
||||
/// </summary>
|
||||
public class TradeForwardUnwindService : TradeServiceBase
|
||||
{
|
||||
public TradeForwardUnwindService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// from fowardTradeController.TradeUnwind
|
||||
/// </summary>
|
||||
public PrepareForwardUnwindResult PrepareUnwind(int tradeId, bool isUseApproval = false)
|
||||
{
|
||||
var result = new PrepareForwardUnwindResult();
|
||||
|
||||
var td = DbContext.trade.Find(tradeId);
|
||||
|
||||
var tc = new trade_cash();
|
||||
|
||||
if (td == null)
|
||||
{
|
||||
throw new ServiceException("找不到现金交割交易");
|
||||
}
|
||||
|
||||
var um = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
|
||||
result.HasProcess = HasTradeProcess();
|
||||
|
||||
if (((valuedateBLL.SystemDate.CloseReCheck == 1) || (valuedateBLL.SystemDate.CloseReApprove == 1 && result.HasProcess)) && td.TradeStatus == ConsTrade.平仓待复核)
|
||||
{
|
||||
tc = DbContext.trade_cash.FirstOrDefault(t => t.TradeId == tradeId && t.Action == ClientCashInCashOut.系统操作_平仓费 && t.ValidState == ConsGlobal.InValid && !t.IsDeleted);
|
||||
|
||||
if (tc == null)
|
||||
{
|
||||
throw new ServiceException("该笔交易状态为平仓待复核,而trade_cash表没有相关记录,请检查该笔交易是否有效");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tc = SetTradeUnwind(td, um);
|
||||
}
|
||||
|
||||
tc.InitialSpotPrice = td.SpotPrice ?? 0;
|
||||
tc.UnderlyingCode = um.UnderlyingCode;
|
||||
tc.UnderlyingId = um.id;
|
||||
tc.TradeOriginalAmount = td.OriginalNotional / um.CountRatio;
|
||||
tc.UnderlyingInstrumentType = td.UnderlyingInstrumentType;
|
||||
tc.BondType = td.TradeType;
|
||||
tc.TradeType = BuySellConvert.GetClientBuySell(td.BuySell);
|
||||
tc.UnwindType = string.IsNullOrEmpty(tc.UnwindType) ? "全部平仓" : tc.UnwindType;
|
||||
|
||||
if (!isUseApproval)
|
||||
{
|
||||
tc.TradeAmount = td.TradeAmount;
|
||||
tc.UnwindPrice = 0;
|
||||
}
|
||||
|
||||
result.Trade = td;
|
||||
result.TradeCash = tc;
|
||||
|
||||
result.OtcTradeForward = new TradeForwardService(OptUser).GetDetail(tradeId);
|
||||
|
||||
if (!string.IsNullOrEmpty(td.PairTrade))
|
||||
{
|
||||
var pid = Convert.ToInt32(td.PairTrade);
|
||||
result.PairTrade = DbContext.trade.Find(pid);
|
||||
}
|
||||
|
||||
result.Underlying = um;
|
||||
result.Variety = new VarietyBasic
|
||||
{
|
||||
CountRatio = um.CountRatio,
|
||||
TradeUnitValue = um.ContractSize,
|
||||
VarietyCode = um.CommodityCode
|
||||
};
|
||||
|
||||
//在当日收盘前部分了解,预付金成本累加获取
|
||||
//远期交易最后一笔平仓时的预付金成本特殊情况处理: 触发条件:
|
||||
//1.最后一笔平仓
|
||||
//2.当前交易日和前一个交易日中间有假期
|
||||
// 处理规则:
|
||||
// 预付金成本 = 这笔平仓上一交易日预付金成本 + 这笔平仓假期日的预付金成本
|
||||
var valueDate = valuedateBLL.ValueDate;
|
||||
|
||||
if (valueDate > td.ExerciseDate)
|
||||
{
|
||||
valueDate = td.ExerciseDate.Value;
|
||||
}
|
||||
|
||||
var lastMarginRecord = DbContext.eod_forward_margin.Where(f => f.TradeId == tc.TradeId && f.ValueDate < valueDate).OrderByDescending(x => x.ValueDate).FirstOrDefault();
|
||||
result.MaxUnwindDate = td.ExerciseDate.Value;
|
||||
if (td.ExerciseDate.Value > valuedateBLL.ValueDate)
|
||||
{
|
||||
result.MaxUnwindDate = valuedateBLL.ValueDate;
|
||||
}
|
||||
|
||||
if (!isUseApproval)
|
||||
{
|
||||
result.TradeCash.ValueDate = valuedateBLL.ValueDate <= td.ExerciseDate ? valuedateBLL.ValueDate : td.ExerciseDate.Value;
|
||||
}
|
||||
|
||||
if (lastMarginRecord != null)
|
||||
{
|
||||
//这段代码注释掉,在前端平仓页面使用MaxUnwindDate限制最大平仓日期选择
|
||||
//var lastSettleDate = QdpCalendarHelper.GetNonHolidayDefore(valueDate.AddDays(-1));
|
||||
//if (lastSettleDate != lastMarginRecord.ValueDate)
|
||||
//{
|
||||
// throw new ServiceException($"请确保上一交易日({lastSettleDate:yyyy-MM-dd})已结算收盘!请尝试从{lastMarginRecord.ValueDate}之后,开始收盘!");
|
||||
//}
|
||||
var totaldays = (valuedateBLL.ValueDate.Date - lastMarginRecord.ValueDate.Date).TotalDays;
|
||||
result.HolidayMargin = lastMarginRecord.SettlePrice * lastMarginRecord.MarginRate * lastMarginRecord.AnnualRate * totaldays / 365;
|
||||
result.LastMarginRecord = lastMarginRecord;
|
||||
}
|
||||
else
|
||||
{
|
||||
//交易日当天
|
||||
result.HolidayMargin = 0;
|
||||
result.LastMarginRecord = new eod_forward_margin();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private trade_cash SetTradeUnwind(trade td, underlying_manager um)
|
||||
{
|
||||
var r = new trade_cash
|
||||
{
|
||||
TradeId = td.id,
|
||||
FinalPrice = um.Price ?? 0,
|
||||
ExceciseType = "现金",
|
||||
CallPut = td.CallPut,
|
||||
Strike = td.Strike,
|
||||
Notional = td.Notional,
|
||||
InitialSpotPrice = td.SpotPrice ?? 0,
|
||||
UnderlyingInstrumentType = td.UnderlyingInstrumentType,
|
||||
StockEqvNotional = td.StockEqvNotional,
|
||||
UnwindNotional = td.Notional,
|
||||
Amount = 0,
|
||||
ValueDate = valuedateBLL.ValueDate <= td.ExerciseDate ? valuedateBLL.ValueDate : td.ExerciseDate.Value,
|
||||
TradeType = BuySellConvert.GetClientBuySell(td.BuySell)
|
||||
};
|
||||
r.TradeAmount = r.Notional / um.CountRatio;
|
||||
r.UnwindTradeAmount = r.UnwindNotional / um.CountRatio;
|
||||
return r;
|
||||
}
|
||||
}
|
||||
|
||||
public class PrepareForwardUnwindResult
|
||||
{
|
||||
public trade Trade { get; set; }
|
||||
|
||||
public trade_cash TradeCash { get; set; }
|
||||
|
||||
public OtcTradeForward OtcTradeForward { get; set; }
|
||||
|
||||
public trade PairTrade { get; set; }
|
||||
|
||||
public underlying_manager Underlying { get; set; }
|
||||
|
||||
public VarietyBasic Variety { get; set; }
|
||||
|
||||
public double HolidayMargin { get; set; }
|
||||
|
||||
public eod_forward_margin LastMarginRecord { get; set; }
|
||||
|
||||
public DateTime MaxUnwindDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 是否有审批步骤
|
||||
/// </summary>
|
||||
public bool HasProcess { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user