从山证v2.3.0拷贝
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,273 @@
|
||||
using Qdp.Pricing.Base.Enums;
|
||||
using YLErp.Configuration;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.OrderModule
|
||||
{
|
||||
partial class TradeAbstractService
|
||||
{
|
||||
/// <summary>
|
||||
/// 雪球期权生成交易摘要
|
||||
/// </summary>
|
||||
private static IEnumerable<(string text, string value)> GenerateTradeAbstract_snowball(trade td, InnerWrap wrap)
|
||||
{
|
||||
if (td is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(td));
|
||||
}
|
||||
|
||||
if (wrap is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(wrap));
|
||||
}
|
||||
|
||||
var snowball = td.trade_snowball;
|
||||
if (snowball == null)
|
||||
{
|
||||
throw new ServiceException("雪球期权扩展信息不存在,无法生成交易摘要");
|
||||
}
|
||||
|
||||
//专业版雪球
|
||||
if (snowball.PrepaymentUsed)
|
||||
{
|
||||
return GenerateTradeAbstract_specialsnowball(td, wrap);
|
||||
}
|
||||
|
||||
td.TradeOriginalAmount = td.OriginalNotional / wrap.CountRatio;
|
||||
|
||||
var list = new List<(string, string)> {
|
||||
("交易编号", td.TradeNumber),
|
||||
("成交日期", td.TradeDate.OtcFormatDate()),
|
||||
("买卖方向", td.ClientName),
|
||||
("#", td.BuySell == "买入" ? "卖出" : "买入"),
|
||||
("标的代码", td.UnderlyingCode),
|
||||
};
|
||||
if (wrap.UnderlyingInstrumentType == "Stock")
|
||||
{
|
||||
list.Add(("标的名称", wrap.UnderlyingName));
|
||||
}
|
||||
list.Add(("期权类型", "雪球 " + td.OptionType));
|
||||
list.Add(("标的价格", td.SpotPrice.OtcFormatUmPrice() + (PS.Config.Is浙期 ? " 元" : "")));
|
||||
if (td.TradeType != "自定义交易" && (td.TradeType != "亚式期权" || td.trade_asian_option.StrikeType != "Floating") && td.TradeType != "雪球期权")
|
||||
{
|
||||
list.Add(("执行价格", wrap.strikeFmt(td.Strike) + (PS.Config.Is浙期 ? " 元" : "")));
|
||||
}
|
||||
|
||||
if (!wrap.IsUsePremiumRate)
|
||||
{
|
||||
list.Add(("成交数量", td.TradeOriginalAmount.OtcFormatNotional(wrap.CountRatio, PS.Config.IsUseDisplayNotional) + (PS.Config.IsUseDisplayNotional ? wrap.QuoteUnit : wrap.TradeUnitString)));
|
||||
}
|
||||
|
||||
if (PS.Config.Is方顿)
|
||||
{
|
||||
list.Add(("保底收益总额", td.OriginalPrincipalSum.OtcFormatMoney() + " 元"));
|
||||
}
|
||||
|
||||
if (PS.Config.Company != CompanyEnum.厦门象屿 && !PS.Config.Is润和)
|
||||
{
|
||||
list.AddRange(new[] {
|
||||
("名义本金", OtcFormatExtensions.OtcFormat(td.StockEqvNotionalToShow, OtcFormatFlag.StockEqvNotional))
|
||||
});
|
||||
}
|
||||
|
||||
if (!snowball.IsInitialKnockedIn)
|
||||
{
|
||||
list.Add(("敲入价格", wrap.strikeFmt(snowball.KIBarrier) + (PS.Config.Is浙期 ? " 元" : "")));
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(("初始敲入", "是"));
|
||||
}
|
||||
list.Add(("敲出价格", wrap.strikeFmt(snowball.KOBarrier) + (PS.Config.Is浙期 ? " 元" : "")));
|
||||
|
||||
switch (snowball.KIPayoffType)
|
||||
{
|
||||
case KIPayoffTypeEnum.None:
|
||||
break;
|
||||
case KIPayoffTypeEnum.ToCallOption:
|
||||
case KIPayoffTypeEnum.ToPutOption:
|
||||
list.Add(("执行价格一", wrap.strikeFmt(snowball.SpreadStrikeAtMaturity1)));
|
||||
break;
|
||||
case KIPayoffTypeEnum.ToCallSpreadOption:
|
||||
case KIPayoffTypeEnum.ToPutSpreadOption:
|
||||
list.Add(("执行价格一", wrap.strikeFmt(snowball.SpreadStrikeAtMaturity)));
|
||||
list.Add(("执行价格二", wrap.strikeFmt(snowball.SpreadStrikeAtMaturity1)));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
var kiObsInfo = "每日观察";
|
||||
if (!string.IsNullOrWhiteSpace(snowball.ObservationDates))
|
||||
{
|
||||
kiObsInfo = snowball.ObservationDates;
|
||||
}
|
||||
switch (snowball.KOPayoffType)
|
||||
{
|
||||
|
||||
case KOPayoffTypeEnum.ToOption:
|
||||
list.Add(("敲出执行价1", wrap.strikeFmt(snowball.SpreadStrikeAtKO1) + (PS.Config.Is浙期 ? " 元" : "")));
|
||||
break;
|
||||
case KOPayoffTypeEnum.ToSpreadOption:
|
||||
list.Add(("敲出执行价1", wrap.strikeFmt(snowball.SpreadStrikeAtKO1) + (PS.Config.Is浙期 ? " 元" : "")));
|
||||
list.Add(("敲出执行价2", wrap.strikeFmt(snowball.SpreadStrikeAtKO) + (PS.Config.Is浙期 ? " 元" : "")));
|
||||
break;
|
||||
case KOPayoffTypeEnum.Rebate:
|
||||
list.Add(("敲出票息", snowball.KORebate.OtcFormatPercent()));
|
||||
break;
|
||||
default:
|
||||
kiObsInfo = "";
|
||||
break;
|
||||
}
|
||||
|
||||
list.Add(("未敲入未敲出收益率", snowball.Coupon.OtcFormat(OtcFormatFlag.percent)));
|
||||
list.Add(("票息年化", snowball.IsFixedCoupon ? "否" : "是"));
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(kiObsInfo) && !snowball.IsInitialKnockedIn)
|
||||
{
|
||||
list.Add(("敲入观察日期", kiObsInfo));
|
||||
}
|
||||
var koInfo = "";
|
||||
if (!string.IsNullOrWhiteSpace(snowball.KOObservationDates))
|
||||
{
|
||||
var KOObservationDates = QdpModule.QdpHelper.ParseAutocallCustomizedInfo(snowball.KOObservationDates);
|
||||
for (var i = 0; i < KOObservationDates.Item1.Length; i++)
|
||||
{
|
||||
var splitStr = ", ";
|
||||
if (i == KOObservationDates.Item1.Length - 1)
|
||||
{
|
||||
splitStr = "";
|
||||
}
|
||||
var couponInfo = PS.Config.Is浙期 ? ":" + KOObservationDates.Item3[i].OtcFormat(OtcFormatFlag.percent) + splitStr : splitStr;
|
||||
koInfo += KOObservationDates.Item1[i].DateTime.ToString("yyyy-MM-dd") + couponInfo;
|
||||
}
|
||||
}
|
||||
|
||||
list.Add(("到期日期", td.ExerciseDate.OtcFormatDate()));
|
||||
list.Add(("敲出观察日期", koInfo));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 专业版雪球期权生成交易摘要
|
||||
/// </summary>
|
||||
private static IEnumerable<(string text, string value)> GenerateTradeAbstract_specialsnowball(trade td, InnerWrap wrap)
|
||||
{
|
||||
if (td is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(td));
|
||||
}
|
||||
|
||||
if (wrap is null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(wrap));
|
||||
}
|
||||
|
||||
var snowball = td.trade_snowball;
|
||||
if (snowball == null)
|
||||
{
|
||||
throw new ServiceException("雪球期权扩展信息不存在,无法生成交易摘要");
|
||||
}
|
||||
|
||||
td.TradeOriginalAmount = td.OriginalNotional / wrap.CountRatio;
|
||||
|
||||
var list = new List<(string, string)> {
|
||||
("交易编号", td.TradeNumber),
|
||||
("成交日期", td.TradeDate.OtcFormatDate()),
|
||||
("买卖方向", td.ClientName),
|
||||
("#", td.BuySell == "买入" ? "卖出" : "买入"),
|
||||
("标的代码", td.UnderlyingCode),
|
||||
};
|
||||
if (wrap.UnderlyingInstrumentType == "Stock")
|
||||
{
|
||||
list.Add(("标的名称", wrap.UnderlyingName));
|
||||
}
|
||||
list.Add(("期权类型", "雪球 " + td.OptionType));
|
||||
list.Add(("标的价格", td.SpotPrice.OtcFormatUmPrice() + (PS.Config.Is浙期 ? " 元" : "")));
|
||||
|
||||
if (!wrap.IsUsePremiumRate)
|
||||
{
|
||||
list.Add(("成交数量", td.TradeOriginalAmount.OtcFormatNotional(wrap.CountRatio, PS.Config.IsUseDisplayNotional) + (PS.Config.IsUseDisplayNotional ? wrap.QuoteUnit : wrap.TradeUnitString)));
|
||||
}
|
||||
|
||||
if (PS.Config.Is方顿)
|
||||
{
|
||||
list.Add(("保底收益总额", td.OriginalPrincipalSum.OtcFormatMoney() + " 元"));
|
||||
}
|
||||
|
||||
if (PS.Config.Company != CompanyEnum.厦门象屿 && !PS.Config.Is润和)
|
||||
{
|
||||
list.AddRange(new[] {
|
||||
("名义本金", OtcFormatExtensions.OtcFormat(td.StockEqvNotionalToShow, OtcFormatFlag.StockEqvNotional))
|
||||
});
|
||||
}
|
||||
|
||||
list.Add(("预付金比例", snowball.PrepaymentRatio.OtcFormatFlex(2, percent: true)));
|
||||
//list.Add(("预付金返息率", snowball.PrepaymentInterestRate.OtcFormatFlex(2, percent: true)));
|
||||
list.Add(("预付金折现率", snowball.PrepaymentConvertCashRate.OtcFormatFlex(2, percent: true)));
|
||||
|
||||
if (snowball.IsInitialKnockedIn)
|
||||
{
|
||||
list.Add(("初始敲入", "是"));
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(("敲入价格", wrap.strikeFmt(snowball.KIBarrier) + (PS.Config.Is浙期 ? " 元" : "")));
|
||||
list.Add(("敲入观察设置", snowball.KIObservationType == KIObservationType.OnlyEndDate ? "仅到期日观察" : "每日观察"));
|
||||
}
|
||||
|
||||
list.Add(("敲入执行价格", wrap.strikeFmt(snowball.SpreadStrikeAtMaturity1) + (PS.Config.Is浙期 ? " 元" : "")));
|
||||
list.Add(("敲入参与率", snowball.KIParticipationRate.OtcFormatFlex(2, percent: true)));
|
||||
list.Add(("保本比率", snowball.PrincipalProtectionRate.OtcFormatFlex(2, percent: true)));
|
||||
|
||||
list.Add(("首日是否计息", snowball.CouponIncludeStartDate == true ? "是" : "否"));
|
||||
list.Add(("终日是否计息", snowball.CouponIncludeEndDate == true ? "是" : "否"));
|
||||
|
||||
var couponDayCount = "非年化";
|
||||
switch (snowball.CouponDayCount)
|
||||
{
|
||||
case nameof(DayCount.Act365):
|
||||
couponDayCount = "按365日年化";
|
||||
break;
|
||||
case nameof(DayCount.Act360):
|
||||
couponDayCount = "按360日年化";
|
||||
break;
|
||||
case nameof(DayCount.Monthly):
|
||||
couponDayCount = "按月年化";
|
||||
break;
|
||||
}
|
||||
list.Add(("计息年化方式", couponDayCount));
|
||||
|
||||
list.Add(("票息率", snowball.KORebate.OtcFormatFlex(2, percent: true)));
|
||||
list.Add(("红利票息", snowball.Coupon.OtcFormatFlex(2, percent: true)));
|
||||
list.Add(("增强参与率", snowball.EnhancedParticipationRate.OtcFormatFlex(2, percent: true)));
|
||||
|
||||
list.Add(("敲出价格", wrap.strikeFmt(snowball.KOBarrier) + (PS.Config.Is浙期 ? " 元" : "")));
|
||||
|
||||
var koInfo = "";
|
||||
if (!string.IsNullOrWhiteSpace(snowball.KOObservationDates))
|
||||
{
|
||||
var KOObservationDates = QdpModule.QdpHelper.ParseAutocallCustomizedInfo(snowball.KOObservationDates);
|
||||
|
||||
if (KOObservationDates != null && KOObservationDates.Item1.Length > 0)
|
||||
{
|
||||
for (var i = 0; i < KOObservationDates.Item1.Length; i++)
|
||||
{
|
||||
var splitStr = ", ";
|
||||
if (i == KOObservationDates.Item1.Length - 1)
|
||||
{
|
||||
splitStr = "";
|
||||
}
|
||||
var couponInfo = PS.Config.Is浙期 ? ":" + KOObservationDates.Item3?[i].OtcFormat(OtcFormatFlag.percent) + splitStr : splitStr;
|
||||
koInfo += KOObservationDates.Item1[i].DateTime.ToString("yyyy-MM-dd") + couponInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
list.Add(("到期日期", td.ExerciseDate.OtcFormatDate()));
|
||||
list.Add(("敲出观察日期", koInfo));
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
using YLErp.BLL;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.OrderModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 交易删除
|
||||
/// </summary>
|
||||
public class TradeInvalidService : TradeServiceBase
|
||||
{
|
||||
public TradeInvalidService(OptUserInfo userInfo) : base(userInfo)
|
||||
{
|
||||
}
|
||||
|
||||
public TradeInvalidService(YLBaseService baseService) : base(baseService)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 无效某条交易
|
||||
/// </summary>
|
||||
public void InvalidTrade(int id, bool needCheckStatus)
|
||||
{
|
||||
var dbTrade = DbContext.trade.Find(id);
|
||||
|
||||
InvalidTrade(dbTrade, needCheckStatus);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 无效某条交易
|
||||
/// </summary>
|
||||
public void InvalidTrade(string tradeNumber, bool needCheckStatus)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(tradeNumber))
|
||||
{
|
||||
throw new ArgumentException($"“{nameof(tradeNumber)}”不能为 null 或空白。", nameof(tradeNumber));
|
||||
}
|
||||
|
||||
var dbTrade = DbContext.trade.FirstOrDefault(n => n.TradeNumber == tradeNumber);
|
||||
|
||||
InvalidTrade(dbTrade, needCheckStatus);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 无效某条交易
|
||||
/// </summary>
|
||||
private void InvalidTrade(trade dbTrade, bool needCheckStatus)
|
||||
{
|
||||
if (dbTrade == null)
|
||||
{
|
||||
throw new ServiceException("找不到交易信息");
|
||||
}
|
||||
|
||||
if (needCheckStatus && dbTrade.TradeStatus != ConsTrade.新增待确认 && dbTrade.TradeStatus != ConsTrade.修改待确认 && dbTrade.TradeStatus != ConsTrade.已拒绝 && (!PS.Config.IsGuoJun ? dbTrade.TradeStatus != ConsTrade.确认成交 : true))
|
||||
{
|
||||
throw new ServiceException($"交易状态为{dbTrade.TradeStatus},不能被删除。");
|
||||
}
|
||||
|
||||
//结构化交易删除子交易,则主交易相关所有记录均会被删除
|
||||
if (dbTrade.ParentTradeId > 0 && dbTrade.TradeType != "收益互换")
|
||||
{
|
||||
dbTrade = DbContext.trade.Find(dbTrade.ParentTradeId);
|
||||
|
||||
if (dbTrade == null)
|
||||
{
|
||||
throw new ServiceException("找不到结构化交易信息");
|
||||
}
|
||||
}
|
||||
|
||||
var ids = new HashSet<int> { dbTrade.id };
|
||||
|
||||
if (dbTrade.TradeType == "结构化交易" || dbTrade.IsGroup == 1)
|
||||
{
|
||||
var subTrades = DbContext.trade.Where(t => t.ParentTradeId == dbTrade.id).ToList();
|
||||
|
||||
InnerInvalidTrade(dbTrade);
|
||||
|
||||
foreach (var subTrade in subTrades)
|
||||
{
|
||||
ids.Add(subTrade.id);
|
||||
|
||||
InnerInvalidTrade(subTrade);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
InnerInvalidTrade(dbTrade);
|
||||
|
||||
//组合收益互换
|
||||
if (dbTrade.ParentTradeId > 0)
|
||||
{
|
||||
var parentTrade = DbContext.trade.Find(dbTrade.ParentTradeId);
|
||||
if (parentTrade != null)
|
||||
{
|
||||
parentTrade.OriginalStockEqvNotional -= dbTrade.OriginalStockEqvNotional;
|
||||
parentTrade.StockEqvNotional -= dbTrade.StockEqvNotional;
|
||||
parentTrade.StockEqvNotionalReal -= dbTrade.StockEqvNotionalReal;
|
||||
var tradePrice = (parentTrade.TradePrice ?? 0) * (parentTrade.BuySell == "买入" ? -1 : 1) - (dbTrade.TradePrice ?? 0) * (dbTrade.BuySell == "买入" ? -1 : 1);
|
||||
parentTrade.TradePrice = Math.Abs(tradePrice);
|
||||
parentTrade.BuySell = tradePrice >= 0 ? "卖出" : "买入";
|
||||
if (parentTrade.StockEqvNotional <= 0)
|
||||
{
|
||||
parentTrade.TradeStatus = "已平仓";
|
||||
}
|
||||
}
|
||||
|
||||
var swapDetail = DbContext.trade_swap_detail.FirstOrDefault(x => x.ChildTradeId == dbTrade.id);
|
||||
if (swapDetail != null)
|
||||
{
|
||||
swapDetail.ValidState = "InValid";
|
||||
}
|
||||
}
|
||||
|
||||
if (dbTrade.TradeType == "收益互换" && PS.Config.IsGuoJun)
|
||||
{
|
||||
var flowid = DbContext.trade_swap.Where(x => x.TradeId == dbTrade.id).Select(x => x.FlowId).ToList();
|
||||
var swapflowmore = DbContext.trade_swap_flow_more.Where(x => flowid.Contains(x.id)).ToList();
|
||||
swapflowmore.ForEach(x =>
|
||||
{
|
||||
x.IsDelete = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
//设置相关提成失效
|
||||
SetCommissionInVaild(ids);
|
||||
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
public void InnerInvalidTrade(trade dbTrade)
|
||||
{
|
||||
dbTrade.OptId = UserId;
|
||||
dbTrade.OptName = UserName;
|
||||
dbTrade.OptDate = OptDate;
|
||||
dbTrade.ValidState = ConsGlobal.InValid;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(dbTrade.TradeNumber))
|
||||
{
|
||||
var contractBll = new TradeContractBLL(UserId, UserName);
|
||||
contractBll.DeleteConfirmBook(dbTrade.id);
|
||||
if (dbTrade.TradeNumber.StartsWith("CW"))
|
||||
{
|
||||
dbTrade.TradeNumber = dbTrade.TradeNumber.Replace("CW", "XX");
|
||||
}
|
||||
else //if (PS.Config.Is光大光子)
|
||||
{
|
||||
dbTrade.TradeNumber = dbTrade.TradeNumber.Insert(0, "XX");
|
||||
}
|
||||
}
|
||||
|
||||
var tradeMarginTemplates = DbContext.trade_margin_template.Where(x => x.TradeId == dbTrade.id);
|
||||
if(tradeMarginTemplates.Any())
|
||||
{
|
||||
DbContext.trade_margin_template.RemoveRange(tradeMarginTemplates);
|
||||
}
|
||||
|
||||
RemoveEodTradeAndFutureInfo(true, dbTrade.id, DateTime.MinValue);
|
||||
new DealModule.TradeConfirmService(this).EditReportStatus(dbTrade.id);
|
||||
AddTradeOperationHistoryAndSetParentTradeInfo(true, dbTrade, "删除交易");
|
||||
}
|
||||
|
||||
//设置相关提成失效
|
||||
public void SetCommissionInVaild(HashSet<int> tradeIds)
|
||||
{
|
||||
var commissions = DbContext.SalesCommissionInfo.Where(o => tradeIds.Contains(o.TradeID)).ToArray();
|
||||
|
||||
foreach (var item in commissions)
|
||||
{
|
||||
item.IsValid = false;
|
||||
item.OptDate = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 批量删除当日交易‘新增待确认’状态的交易
|
||||
/// </summary>
|
||||
public int InvalidTodayUnconfirmedTrades(HashSet<int> ids)
|
||||
{
|
||||
if (ids is null || !ids.Any())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var valueDate = valuedateBLL.ValueDate;
|
||||
var tradeList = DbContext.trade.Where(t => t.TradeDate == valueDate && ids.Contains(t.id) && t.ValidState != ConsGlobal.InValid && t.TradeStatus == ConsTrade.新增待确认).ToList();
|
||||
if (!tradeList.Any())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
var pids = tradeList.Select(n => n.ParentTradeId).ToHashSet();
|
||||
pids.Remove(0);
|
||||
if (pids.Any())
|
||||
{
|
||||
var pTrades = DbContext.trade.Where(t => t.TradeDate == valueDate && !ids.Contains(t.id) && (pids.Contains(t.id) || pids.Contains(t.ParentTradeId))).ToArray();
|
||||
|
||||
tradeList.AddRange(pTrades);
|
||||
}
|
||||
|
||||
var childrenTrades = DbContext.trade.Where(t => t.TradeDate == valueDate && !ids.Contains(t.id) && ids.Contains(t.ParentTradeId)).ToArray();
|
||||
if (childrenTrades.Any())
|
||||
{
|
||||
tradeList.AddRange(childrenTrades);
|
||||
}
|
||||
|
||||
foreach (var t in tradeList)
|
||||
{
|
||||
ids.Add(t.id);
|
||||
InnerInvalidTrade(t);
|
||||
}
|
||||
|
||||
SetCommissionInVaild(ids);
|
||||
|
||||
DbContext.SaveChanges();
|
||||
|
||||
return tradeList.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
using Qdp.Pricing.Base.Enums;
|
||||
using YLErp.QdpModule;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.OrderModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 扩展存储
|
||||
/// </summary>
|
||||
class TradeSaveExtend : YLBaseService
|
||||
{
|
||||
private readonly bool isAddNew;
|
||||
|
||||
public TradeSaveExtend(YLBaseService baseService, bool isAddNew)
|
||||
: base(baseService)
|
||||
{
|
||||
this.isAddNew = isAddNew;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 保存并写入数据库
|
||||
/// </summary>
|
||||
public int Save(trade baseTrade, trade dbTrade, bool useSaveChange = true)
|
||||
{
|
||||
switch (baseTrade.TradeType == "结构化交易" ? baseTrade.StructureType : baseTrade.TradeType)
|
||||
{
|
||||
case "香草期权":
|
||||
case "合成价差期权":
|
||||
return 0;
|
||||
case "亚式期权":
|
||||
dbTrade.trade_asian_option = InnerSaveExtend(baseTrade, baseTrade.trade_asian_option);
|
||||
break;
|
||||
case "彩虹期权":
|
||||
dbTrade.trade_rainbow_option = InnerSaveExtend(baseTrade, baseTrade.trade_rainbow_option);
|
||||
break;
|
||||
case "障碍期权":
|
||||
dbTrade.trade_barrier_option = InnerSaveExtend(baseTrade, baseTrade.trade_barrier_option);
|
||||
break;
|
||||
case "二元期权":
|
||||
dbTrade.trade_binary_option = InnerSaveExtend(baseTrade, baseTrade.trade_binary_option);
|
||||
break;
|
||||
case "价差期权":
|
||||
dbTrade.trade_spread_option = InnerSaveExtend(baseTrade, baseTrade.trade_spread_option);
|
||||
break;
|
||||
case "双鲨期权":
|
||||
dbTrade.trade_double_sharkfin_option = InnerSaveExtend(baseTrade, baseTrade.trade_double_sharkfin_option);
|
||||
break;
|
||||
case "凤凰期权":
|
||||
if (string.IsNullOrEmpty(baseTrade.trade_autocall.KOObservationDates))
|
||||
{
|
||||
if (dbTrade.trade_autocall==null)
|
||||
{
|
||||
dbTrade.trade_autocall = new trade_autocall();
|
||||
}
|
||||
var autocallmonthlyDates = QdpObservationHelper.GetDatesWithFixedTerm(baseTrade.TradeDate ?? System.DateTime.Now, baseTrade.ExerciseDate ?? System.DateTime.Now, "1M", bdc: BusinessDayConvention.Following, alignEnd: true);
|
||||
dbTrade.trade_autocall.KOObservationDates = $"{string.Join(",", autocallmonthlyDates.Select(O => O.OtcFormatDate()))};" +
|
||||
$"{string.Join(",", autocallmonthlyDates.Select(O => baseTrade.trade_autocall.KOBarrier.OtcFormatFlex(2)))};" +
|
||||
$"{string.Join(",", autocallmonthlyDates.Select(O => baseTrade.trade_autocall.Coupon.OtcFormatFlex(2)))}";
|
||||
baseTrade.trade_autocall.KOObservationDates = dbTrade.trade_autocall.KOObservationDates;
|
||||
}
|
||||
dbTrade.trade_autocall = InnerSaveExtend(baseTrade, baseTrade.trade_autocall);
|
||||
break;
|
||||
case "雪球期权":
|
||||
if (string.IsNullOrEmpty(baseTrade.trade_snowball.KOObservationDates))
|
||||
{
|
||||
if (dbTrade.trade_snowball == null)
|
||||
{
|
||||
dbTrade.trade_snowball = new trade_snowball();
|
||||
}
|
||||
var snowballmonthlyDates = QdpObservationHelper.GetDatesWithFixedTerm(baseTrade.TradeDate ?? System.DateTime.Now, baseTrade.ExerciseDate ?? System.DateTime.Now, "1M", bdc: BusinessDayConvention.Following, alignEnd: true);
|
||||
|
||||
dbTrade.trade_snowball.KOObservationDates = $"{string.Join(",", snowballmonthlyDates.Select(O => O.OtcFormatDate()))};" +
|
||||
$"{string.Join(",", snowballmonthlyDates.Select(O => baseTrade.trade_snowball.KOBarrier.OtcFormatFlex(2)))};" +
|
||||
$"{string.Join(",", snowballmonthlyDates.Select(O => baseTrade.trade_snowball.KORebate.OtcFormatFlex(2)))}";
|
||||
if (dbTrade.trade_snowball.KOPayoffType == KOPayoffTypeEnum.Rebate)
|
||||
{
|
||||
baseTrade.trade_snowball.KOObservationSettleDates = $"{string.Join(",", snowballmonthlyDates.Select(O => O.OtcFormatDate()))}";
|
||||
}
|
||||
baseTrade.trade_snowball.KOObservationDates = dbTrade.trade_snowball.KOObservationDates;
|
||||
}
|
||||
dbTrade.trade_snowball = InnerSaveExtend(baseTrade, baseTrade.trade_snowball);
|
||||
break;
|
||||
case "区间累积期权":
|
||||
dbTrade.trade_rangeaccrual = InnerSaveExtend(baseTrade, baseTrade.trade_rangeaccrual);
|
||||
break;
|
||||
case "气囊结构":
|
||||
dbTrade.trade_airbag = InnerSaveExtend(baseTrade, baseTrade.trade_airbag);
|
||||
break;
|
||||
case "收益增强结构":
|
||||
dbTrade.trade_underlying_enhance = InnerSaveExtend(baseTrade, baseTrade.trade_underlying_enhance);
|
||||
break;
|
||||
case "远期":
|
||||
dbTrade.trade_forward = InnerSaveExtend(baseTrade, baseTrade.trade_forward);
|
||||
break;
|
||||
case "收益互换":
|
||||
if (baseTrade.trade_swap.IsGetFloatingProfit)
|
||||
{
|
||||
var underlyingManager = DataCacheProvider.GetUnderlyingDataSource().GetData(baseTrade.trade_swap.GetUnderlyingCode);
|
||||
var CountRatio = underlyingManager?.CountRatio ?? 1;
|
||||
baseTrade.trade_swap.GetNotional = baseTrade.trade_swap.GetTradeAmount * CountRatio;
|
||||
|
||||
dbTrade.OriginalNotional = baseTrade.trade_swap.GetNotional;
|
||||
dbTrade.Notional = baseTrade.trade_swap.GetNotional ?? 0;
|
||||
dbTrade.TradeAmount = baseTrade.trade_swap.GetTradeAmount ?? 0;
|
||||
dbTrade.SpotPrice = baseTrade.trade_swap.GetSpotPrice;
|
||||
}
|
||||
if (baseTrade.trade_swap.IsPayFloatingProfit)
|
||||
{
|
||||
var underlyingManager = DataCacheProvider.GetUnderlyingDataSource().GetData(baseTrade.trade_swap.PayUnderlyingCode);
|
||||
var CountRatio = underlyingManager?.CountRatio ?? 1;
|
||||
baseTrade.trade_swap.PayNotional = baseTrade.trade_swap.PayTradeAmount * CountRatio;
|
||||
|
||||
dbTrade.OriginalNotional = baseTrade.trade_swap.PayNotional;
|
||||
dbTrade.Notional = baseTrade.trade_swap.PayNotional ?? 0;
|
||||
dbTrade.TradeAmount = baseTrade.trade_swap.PayTradeAmount ?? 0;
|
||||
dbTrade.SpotPrice = baseTrade.trade_swap.PaySpotPrice;
|
||||
}
|
||||
DbContext.SaveChanges();
|
||||
dbTrade.trade_swap = InnerSaveExtend(baseTrade, baseTrade.trade_swap);
|
||||
dbTrade.get_trade_swap_details = InnerSaveTradeSwapDetail(baseTrade, baseTrade.get_trade_swap_details, true);
|
||||
dbTrade.pay_trade_swap_details = InnerSaveTradeSwapDetail(baseTrade, baseTrade.pay_trade_swap_details, false);
|
||||
if (baseTrade.ParentTradeId > 0)
|
||||
{
|
||||
var detail = DbContext.trade_swap_detail.FirstOrDefault(x => x.TradeId == baseTrade.ParentTradeId && x.ChildTradeId == baseTrade.id);
|
||||
if (detail != null)
|
||||
{
|
||||
detail.LongShort = detail.IsForGet ? baseTrade.trade_swap.GetLongShort : baseTrade.trade_swap.PayLongShort;
|
||||
detail.Notional = detail.IsForGet ? baseTrade.trade_swap.GetNotional : baseTrade.trade_swap.PayNotional;
|
||||
detail.UnderlyingCode = detail.IsForGet ? baseTrade.trade_swap.GetUnderlyingCode : baseTrade.trade_swap.PayUnderlyingCode;
|
||||
detail.SpotPrice = detail.IsForGet ? baseTrade.trade_swap.GetSpotPrice : baseTrade.trade_swap.PaySpotPrice;
|
||||
detail.OriginalNotional = detail.Notional;
|
||||
}
|
||||
else
|
||||
{
|
||||
detail = new trade_swap_detail()
|
||||
{
|
||||
IsForGet = baseTrade.trade_swap.IsGetFloatingProfit
|
||||
};
|
||||
detail.LongShort = detail.IsForGet ? baseTrade.trade_swap.GetLongShort : baseTrade.trade_swap.PayLongShort;
|
||||
detail.Notional = detail.IsForGet ? baseTrade.trade_swap.GetNotional : baseTrade.trade_swap.PayNotional;
|
||||
detail.UnderlyingCode = detail.IsForGet ? baseTrade.trade_swap.GetUnderlyingCode : baseTrade.trade_swap.PayUnderlyingCode;
|
||||
detail.SpotPrice = detail.IsForGet ? baseTrade.trade_swap.GetSpotPrice : baseTrade.trade_swap.PaySpotPrice;
|
||||
detail.OriginalNotional = detail.Notional;
|
||||
detail.TradeId = baseTrade.ParentTradeId;
|
||||
detail.ChildTradeId = baseTrade.id;
|
||||
DbContext.trade_swap_detail.Add(detail);
|
||||
}
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
break;
|
||||
case "现金流交易":
|
||||
dbTrade.trade_cashflow = InnerSaveExtend(baseTrade, baseTrade.trade_cashflow);
|
||||
break;
|
||||
case "自定义交易":
|
||||
dbTrade.trade_custom = InnerSaveExtend(baseTrade, baseTrade.trade_custom);
|
||||
break;
|
||||
case "累计期权":
|
||||
dbTrade.trade_accumulator_option = InnerSaveExtend(baseTrade, baseTrade.trade_accumulator_option);
|
||||
break;
|
||||
case "Risky期权":
|
||||
dbTrade.trade_risky_option = InnerSaveExtend(baseTrade, baseTrade.trade_risky_option);
|
||||
break;
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
return useSaveChange ? DbContext.SaveChanges() : 0;
|
||||
}
|
||||
|
||||
private List<trade_swap_detail> InnerSaveTradeSwapDetail(trade baseTrade, List<trade_swap_detail> tradeSwapDetails, bool isForGet)
|
||||
{
|
||||
if (tradeSwapDetails != null && tradeSwapDetails.Any())
|
||||
{
|
||||
var tradeSwapDetailsExist = DbContext.trade_swap_detail.Where(x => x.TradeId == baseTrade.id && x.IsForGet == isForGet);
|
||||
DbContext.trade_swap_detail.RemoveRange(tradeSwapDetailsExist);
|
||||
tradeSwapDetails.ForEach(x =>
|
||||
{
|
||||
x.ExerciseDate = baseTrade.ExerciseDate;
|
||||
x.IsForGet = isForGet;
|
||||
x.OriginalNotional = x.Notional;
|
||||
x.SwapTimeAndRate = isForGet ? baseTrade.trade_swap.PaySwapTimeAndRate : baseTrade.trade_swap.GetSwapTimeAndRate;
|
||||
x.TradeId = baseTrade.id;
|
||||
SetDBModelOpt(x);
|
||||
});
|
||||
DbContext.trade_swap_detail.AddRange(tradeSwapDetails);
|
||||
DbContext.SaveChanges();
|
||||
}
|
||||
|
||||
return tradeSwapDetails;
|
||||
}
|
||||
|
||||
//保存扩展数据
|
||||
private T InnerSaveExtend<T>(trade baseTrade, T extend) where T : TradeExtendBase
|
||||
{
|
||||
SetDBModelOpt(extend);
|
||||
|
||||
extend.TradeId = baseTrade.id;
|
||||
|
||||
var exist = isAddNew ? null : DbContext.Set<T>().FirstOrDefault(n => n.TradeId == baseTrade.id);
|
||||
|
||||
if (exist == null)
|
||||
{
|
||||
extend.id = 0;
|
||||
DbContext.Set<T>().Add(extend);
|
||||
}
|
||||
else
|
||||
{
|
||||
extend.id = exist.id;
|
||||
UpdateEntity(exist, extend);
|
||||
}
|
||||
return extend;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,51 @@
|
||||
namespace YLErp.Modules.TradeModule.OrderModule
|
||||
{
|
||||
partial class TradeSavePreHandler
|
||||
{
|
||||
private static void CheckSnowball(trade req)
|
||||
{
|
||||
var snowball = req.trade_snowball;
|
||||
|
||||
if (snowball.PrepaymentUsed)
|
||||
{
|
||||
if (snowball.SpreadStrikeAtMaturity1 == null)
|
||||
{
|
||||
throw new ServiceException("敲入执行价格 必须填写");
|
||||
}
|
||||
|
||||
snowball.KOObservationDates = snowball.KOObservationDates?.Trim(new[] { ' ', ';' });
|
||||
|
||||
if (string.IsNullOrWhiteSpace(snowball.KOObservationDates))
|
||||
{
|
||||
throw new ServiceException("敲出观察频率 必须填写");
|
||||
}
|
||||
|
||||
req.Strike = snowball.SpreadStrikeAtMaturity1;
|
||||
|
||||
snowball.IsAnnualized2 = false;
|
||||
snowball.AnnualizeFactor2 = 1;
|
||||
req.MetaDic[nameof(snowball.AnnualizeFactor2)] = "/";
|
||||
|
||||
snowball.KOPayoffType = KOPayoffTypeEnum.Rebate;
|
||||
snowball.KIPayoffType = KIPayoffTypeEnum.Prepayment;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!snowball.IsAnnualized2 || !snowball.AnnualizeFactor2.HasValue)
|
||||
{
|
||||
snowball.AnnualizeFactor2 = 1;
|
||||
req.MetaDic[nameof(snowball.AnnualizeFactor2)] = "/";
|
||||
}
|
||||
|
||||
if (snowball.KIPayoffType == KIPayoffTypeEnum.None)
|
||||
{
|
||||
req.Strike = req.IsMoneynessOptionData ? 1 : req.SpotPrice;
|
||||
}
|
||||
else
|
||||
{
|
||||
req.Strike = snowball.SpreadStrikeAtMaturity1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,537 @@
|
||||
using YLErp.BLL;
|
||||
using YLErp.BLL.Eod;
|
||||
using YLErp.Configuration;
|
||||
using YLErp.Modules.CalculationModule;
|
||||
|
||||
namespace YLErp.Modules.TradeModule.OrderModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 不要再合并3.9
|
||||
/// </summary>
|
||||
public class TradeTerminationAbstractService
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public static string GetAbstractInfoText(trade_cash tc, trade td, bool isUnwind, bool useHeader = false, bool derive = false)
|
||||
{
|
||||
var items = isUnwind ? GetUnwindAbstractInfoItems(tc, td).ToList() : GetExerciseAbstractInfoItems(tc, td).ToList();
|
||||
|
||||
var bodyIndent = string.Empty;
|
||||
|
||||
if (items.Any())
|
||||
{
|
||||
//var maxLen = items.Max(n => n.text.Length);
|
||||
//bodyIndent = new string(' ', maxLen + 1);
|
||||
//items = items.Select(n => (n.text == "#" ? bodyIndent : n.text.PadLeft(maxLen, ' '), n.value)).ToList();
|
||||
|
||||
items = items.Select(n => (n.text == "#" ? new string(' ', 5) : n.text, n.value)).ToList();
|
||||
}
|
||||
|
||||
var headIndent = bodyIndent.Length > 3 ? bodyIndent.Substring(0, bodyIndent.Length - 3) : string.Empty;
|
||||
|
||||
var list = new List<(string text, string value)>();
|
||||
|
||||
if (derive == true)
|
||||
{
|
||||
list = new List<(string text, string value)>() {
|
||||
(headIndent, PS.Config.CompanyName),
|
||||
(headIndent, "【场外了结记录摘要】"),
|
||||
(string.Empty, "####")
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
list = new List<(string text, string value)>();
|
||||
}
|
||||
|
||||
|
||||
list.AddRange(items);
|
||||
return string.Join("\r\n", list.Select(
|
||||
n => string.IsNullOrEmpty(n.text) ? n.value : n.text.EndsWith(" ") ? n.text + n.value : n.text + ":" + n.value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成平仓摘要
|
||||
/// </summary>
|
||||
public static IEnumerable<(string text, string value)> GetUnwindAbstractInfoItems(trade_cash tc, trade td)
|
||||
{
|
||||
if (td.TradeType == "远期")
|
||||
{
|
||||
return GetUnwindAbstractInfoItems_Forward(tc, td);
|
||||
}
|
||||
|
||||
if (td.TradeType == "雪球期权")
|
||||
{
|
||||
return GetUnwindAbstractInfoItems_snowball(tc, td, true);
|
||||
}
|
||||
|
||||
if (td.TradeType == "现金流交易")
|
||||
{
|
||||
return GetUnwindAbstractInfoItems_cashflow(tc, td);
|
||||
}
|
||||
|
||||
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
|
||||
var QuoteUnitString = " 元/" + (PS.Config.IsUseDisplayNotional ? underlying.QuoteUnitString : underlying.TradeUnitString);
|
||||
var IsUsePremiumRate = td.IsUsePremiumRate == true;
|
||||
var SpotPrice = underlying.UnderlyingInstrumentType == "CommodityFutures" ? td.SpotPrice : td.InitialSpotPrice;
|
||||
var strikeFmt = new Func<double?, string>(d => d.OtcFormatUmPrice(td.IsMoneynessOption == "是"));
|
||||
|
||||
var premiumFmt = IsUsePremiumRate
|
||||
? new Func<double?, string>(d => OtcFormatExtensions.OtcFormat(d, OtcFormatFlag.premiumRateP))
|
||||
: new Func<double?, string>(d => OtcFormatExtensions.OtcFormat(d, OtcFormatFlag.tradeSinglePrice));
|
||||
|
||||
var tradeAmount = td.TradeAmount.OtcFormatNotional() + (td.UnderlyingInstrumentType == "Stock"
|
||||
? " 股" : " " + td.QuoteUnitSingle);
|
||||
var tradeType = GetTradeType(td);
|
||||
var istrade_barrier = td.TradeType == "障碍期权";
|
||||
//如果是组合标的
|
||||
if (underlying.UnderlyingType == "组合标的")
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(td.SyntheticUnderlyingTipsInfo))
|
||||
{
|
||||
td.UnderlyingCode = td.SyntheticUnderlyingTipsInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
td.UnderlyingCode = synthetic_underlyingBLL.GetUnderlyingTipsInfo(td.UnderlyingCode);
|
||||
}
|
||||
}
|
||||
var list = new List<(string, string)>();
|
||||
if (PS.Config.Is厦门象屿)
|
||||
{
|
||||
list.Add(("平仓信息", ""));
|
||||
}
|
||||
list.AddRange(new[]{
|
||||
("交易编号", td.TradeNumber),
|
||||
("开仓日期", td.TradeDate.OtcFormatDate()),
|
||||
("开仓方向", td.ClientName),
|
||||
("#", td.BuySell == "买入" ? "卖出" : "买入"),
|
||||
("期权类型",(PS.Config.Is光大光子 && td.TradeType=="自定义交易")?td.StructureIntroduction : tradeType),
|
||||
("标的代码",td.UnderlyingCode),
|
||||
});
|
||||
if (istrade_barrier)
|
||||
{
|
||||
list.Add(("观察频率", td.trade_barrier_option.ObservationDates ?? "每日观察"));
|
||||
list.Add(("报价单位", QuoteUnitString));
|
||||
list.Add(("障碍水平", strikeFmt(td.trade_barrier_option.BarrierPrice)));
|
||||
}
|
||||
var actualExerciseDate = td.ExerciseDate;
|
||||
if (td.MetaDic == null || td.MetaDic.Count == 0)
|
||||
{
|
||||
var exerciseDate = new TradeMetaService(OptUserInfo.SystemUser).GetTradeMeta(td.id, "ActualExerciseDate");
|
||||
if (!string.IsNullOrWhiteSpace(exerciseDate) && DateTime.TryParse(exerciseDate, out var tempDate))
|
||||
{
|
||||
actualExerciseDate = tempDate;
|
||||
}
|
||||
}
|
||||
list.Add(("执行价格", strikeFmt(td.Strike)));
|
||||
list.Add(("到期日期", actualExerciseDate.OtcFormatDate()));
|
||||
if (istrade_barrier)
|
||||
{
|
||||
list.Add(("补偿金额", IsUsePremiumRate ? premiumFmt(td.trade_barrier_option.RebateRate) : strikeFmt(td.trade_barrier_option.Rebate)));
|
||||
list.Add(("高障碍补偿金额", IsUsePremiumRate ? premiumFmt(td.trade_barrier_option.RebateHighRate) : strikeFmt(td.trade_barrier_option.RebateHigh)));
|
||||
list.Add(("补偿支付", td.trade_barrier_option.RebateTypeCn));
|
||||
}
|
||||
list.Add(("平仓日期", tc.ValueDate.OtcFormatDate()));
|
||||
|
||||
bool ActualHasMinusValueOptions = valuedateBLL.SystemDate.UnwindSinglePriceAngle == 1 ? ConsTrade.HasMinusValueOptions.Contains(td.TradeType) : !ConsTrade.HasMinusValueOptions.Contains(td.TradeType);
|
||||
|
||||
if (IsUsePremiumRate)
|
||||
{
|
||||
list.Add(("标的价格", td.SpotPrice.OtcFormatUmPrice() + " (开仓)"));
|
||||
list.Add((new string(' ', 5), tc.FinalPrice.OtcFormatUmPrice() + " (平仓)"));
|
||||
|
||||
var premiumRate = td.PremiumRate * (valuedateBLL.SystemDate.UnwindSinglePriceAngle == 1 ? EodOperationBase.GetSign(td.BuySell) : 1);
|
||||
list.Add(("期权费率", premiumFmt(premiumRate) + " (开仓) "));
|
||||
|
||||
//计算出交易员角度的值
|
||||
var unwindPricePercentRate = tc.UnwindPricePercentRate * (ActualHasMinusValueOptions ? 1 : EodOperationBase.GetSign(td.BuySell));
|
||||
//结算视角需要客户视角
|
||||
unwindPricePercentRate *= (valuedateBLL.SystemDate.UnwindSinglePriceAngle == 1 ? -1 : 1);
|
||||
list.Add((new string(' ', 5), premiumFmt(unwindPricePercentRate) + "(平仓)"));
|
||||
}
|
||||
else
|
||||
{
|
||||
using (var db = DbContextFactory.GetYLDbContext())
|
||||
{
|
||||
list.Add(("标的价格", td.SpotPrice.OtcFormatUmPrice() + " (开仓)"));
|
||||
list.Add((new string(' ', 5), tc.FinalPrice.OtcFormatUmPrice() + " (平仓)"));
|
||||
|
||||
var openPrice = td.TradeSinglePrice * (valuedateBLL.SystemDate.UnwindSinglePriceAngle == 1 ? EodOperationBase.GetSign(td.BuySell) : 1);
|
||||
list.Add((" 权利金", premiumFmt(openPrice) + " (开仓) "));
|
||||
|
||||
//计算出交易员角度的值
|
||||
var unwindPrice = tc.UnwindPrice * (ActualHasMinusValueOptions ? 1 : EodOperationBase.GetSign(td.BuySell));
|
||||
//结算视角需要客户视角
|
||||
unwindPrice *= (valuedateBLL.SystemDate.UnwindSinglePriceAngle == 1 ? -1 : 1);
|
||||
list.Add((new string(' ', 5), premiumFmt(unwindPrice) + "(平仓)"));
|
||||
}
|
||||
}
|
||||
var amount = tc.Amount * (valuedateBLL.SystemDate.UnwindAmountAngle == 1 ? -1 : EodOperationBase.GetSign(td.BuySell));
|
||||
if (IsUsePremiumRate)
|
||||
{
|
||||
list.AddRange(new[] {
|
||||
("平仓比例", tc.UnwindPercentRate.OtcFormatPercent()),
|
||||
("平仓总额", (amount).OtcFormatMoney()+"元"),
|
||||
("实现盈亏",(-TradeCalcHelper.CalcChildTradeSumWinLoss(td,tc,IsUsePremiumRate,underlying.CountRatio)).OtcFormatMoney()+" 元")
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
list.AddRange(new[] {
|
||||
("平仓数量",(td.UnderlyingInstrumentType=="Stock"?tc.UnwindNotional.OtcFormatNotional()+"股":
|
||||
tc.UnwindTradeAmount.OtcFormatNotional(underlying.CountRatio,PS.Config.IsUseDisplayNotional)+ " " +(td.QuoteUnitSingle == "吨" &&PS.Config.IsUseDisplayNotional&& underlying.UnderlyingType == "鸡蛋" ? "半吨":td.QuoteUnitSingle) )),
|
||||
("平仓总额", (amount).OtcFormatMoney()+"元"),
|
||||
("实现盈亏",(-TradeCalcHelper.CalcChildTradeSumWinLoss(td,tc,IsUsePremiumRate,underlying.CountRatio)).OtcFormatMoney()+" 元")
|
||||
});
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 生成行权摘要
|
||||
/// </summary>
|
||||
public static IEnumerable<(string text, string value)> GetExerciseAbstractInfoItems(trade_cash tc, trade td)
|
||||
{
|
||||
|
||||
if (td.TradeType == "雪球期权")
|
||||
{
|
||||
return GetUnwindAbstractInfoItems_snowball(tc, td, false);
|
||||
}
|
||||
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
|
||||
var IsUsePremiumRate = td.IsUsePremiumRate == true;
|
||||
var QuoteUnitString = "";
|
||||
if (underlying != null)
|
||||
{
|
||||
QuoteUnitString = " 元/" + (PS.Config.IsUseDisplayNotional ? underlying.QuoteUnitString : underlying.TradeUnitString);
|
||||
var SpotPrice = underlying.UnderlyingInstrumentType == "CommodityFutures" ? td.SpotPrice : td.InitialSpotPrice;
|
||||
}
|
||||
///行权价格式
|
||||
var strikeFmt = new Func<double?, string>(d => d.OtcFormatUmPrice(td.IsMoneynessOption == "是"));
|
||||
|
||||
var premiumFmt = IsUsePremiumRate
|
||||
? new Func<double?, string>(d => OtcFormatExtensions.OtcFormat(d, OtcFormatFlag.premiumRateP))
|
||||
: new Func<double?, string>(d => OtcFormatExtensions.OtcFormat(d, OtcFormatFlag.tradeSinglePrice));
|
||||
var single = new Func<double?, string>(d => OtcFormatExtensions.OtcFormat(d, OtcFormatFlag.tradeSinglePrice));
|
||||
var tradeAmount = td.TradeAmount.OtcFormatNotional() + (td.UnderlyingInstrumentType == "Stock"
|
||||
? " 股" : " " + td.QuoteUnitSingle);
|
||||
var istrade_barrier = td.TradeType == "障碍期权";
|
||||
var actionName = "行权";
|
||||
|
||||
//如果是组合标的
|
||||
if (underlying != null)
|
||||
{
|
||||
if (underlying.UnderlyingType == "组合标的")
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(td.SyntheticUnderlyingTipsInfo))
|
||||
{
|
||||
td.UnderlyingCode = td.SyntheticUnderlyingTipsInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
td.UnderlyingCode = synthetic_underlyingBLL.GetUnderlyingTipsInfo(td.UnderlyingCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
var list = new List<(string, string)>();
|
||||
if (PS.Config.Is厦门象屿)
|
||||
{
|
||||
list.Add(("行权信息", ""));
|
||||
}
|
||||
list.AddRange(new[] {
|
||||
("交易编号", td.TradeNumber),
|
||||
("开仓日期", td.TradeDate.OtcFormatDate()),
|
||||
("开仓方向", td.ClientName),
|
||||
("#", td.BuySell == "买入" ? "卖出" : "买入"),
|
||||
("期权类型", td.StructureType!=null?td.StructureType: GetTradeType(td)),
|
||||
("标的代码",td.UnderlyingCode),
|
||||
});
|
||||
if (istrade_barrier)
|
||||
{
|
||||
list.Add(("观察频率", td.trade_barrier_option.ObservationDates ?? "每日观察"));
|
||||
list.Add(("报价单位", QuoteUnitString));
|
||||
list.Add(("障碍水平", strikeFmt(td.trade_barrier_option.BarrierPrice)));
|
||||
}
|
||||
if (td.TradeType != "雪球期权" && td.TradeType != "凤凰期权")
|
||||
{
|
||||
list.Add(("执行价格", strikeFmt(td.Strike)));
|
||||
}
|
||||
list.Add(("到期日期", td.ExerciseDate.OtcFormatDate()));
|
||||
if (istrade_barrier)
|
||||
{
|
||||
tradeBLL.SetFieldsByTradeType(td);
|
||||
list.Add(("补偿金额", IsUsePremiumRate ? premiumFmt(td.trade_barrier_option.RebateRate) : premiumFmt(td.trade_barrier_option.Rebate)));
|
||||
list.Add(("高障碍补偿金额", IsUsePremiumRate ? premiumFmt(td.trade_barrier_option.RebateHighRate) : strikeFmt(td.trade_barrier_option.RebateHigh)));
|
||||
list.Add(("补偿支付", td.trade_barrier_option.RebateTypeCn));
|
||||
}
|
||||
if (IsUsePremiumRate)
|
||||
{
|
||||
list.Add(("期权费率", premiumFmt(td.PremiumRate) + " (开仓) "));
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add((" 权利金", premiumFmt(td.TradeSinglePrice ?? 0) + " (开仓) "));
|
||||
}
|
||||
|
||||
list.Add(($"{actionName}日期", tc.ValueDate.ToString("yyyy-MM-dd")));
|
||||
if (td.UnderlyingInstrumentType == "CommodityFutures")
|
||||
{
|
||||
list.Add(("标的价格", td.SpotPrice.OtcFormatUmPrice() + " (开仓)"));
|
||||
list.Add((new string(' ', 5), (tc.FinalPrice ?? 0).OtcFormatUmPrice() + (PS.Config.Is厦门象屿 ? "(到期)" : "(行权)")));
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(("标的价格", td.InitialSpotPrice.OtcFormatUmPrice() + " (开仓)"));
|
||||
list.Add((new string(' ', 5), tc.FinalPrice.OtcFormatUmPrice() + $" ({actionName})"));
|
||||
}
|
||||
var UnwindPrice = 0.00;
|
||||
if (tc.UnwindPrice == null)
|
||||
{
|
||||
UnwindPrice = 0.00;
|
||||
}
|
||||
else
|
||||
{
|
||||
UnwindPrice = Math.Abs(tc.UnwindPrice.Value);
|
||||
}
|
||||
if (underlying != null)
|
||||
{
|
||||
list.AddRange(new[] {
|
||||
($"{actionName}收益",single(UnwindPrice)+ " 元"),
|
||||
($"{actionName}数量",(tc.IsLastAction? tc.Notional / underlying.CountRatio: (tc.UnwindTradeAmount!=null?tc.UnwindTradeAmount:0.0000)).OtcFormatNotional(underlying.CountRatio,PS.Config.IsUseDisplayNotional)+ " " +(PS.Config.IsUseDisplayNotional ? underlying.QuoteUnitString : underlying.TradeUnitString)),
|
||||
($"{actionName}总额",(-tc.Amount).OtcFormatMoney()+ " 元"),
|
||||
});
|
||||
}
|
||||
list.Add(("实现盈亏", (-TradeCalcHelper.CalcChildTradeSumWinLoss(td, tc)).OtcFormatMoney() + " 元"));
|
||||
return list;
|
||||
}
|
||||
|
||||
private static string GetTradeType(trade td)
|
||||
{
|
||||
var result = "";
|
||||
switch (td.StructureType ?? td.TradeType)
|
||||
{
|
||||
case "远期":
|
||||
case "掉期":
|
||||
result = (td.StructureType.TrimToNull() ?? td.TradeType) + (td.OptionType == "看涨" || td.OptionType == "多头" ? "多头" : "空头");
|
||||
break;
|
||||
case "二元期权":
|
||||
result = td.ExerciseMode == "American" ? td.ExerciseModeCn + td.TradeType.Replace("期权", "") + "期权" : td.ExerciseModeCn + td.TradeType.Replace("期权", "") + td.OptionType + "期权";
|
||||
break;
|
||||
case "雪球期权":
|
||||
result = "雪球 " + td.OptionType;
|
||||
break;
|
||||
case "双鲨期权":
|
||||
result = td.ExerciseModeCn + td.TradeType.Replace("期权", "") + td.OptionType + "期权";
|
||||
break;
|
||||
case "亚式期权":
|
||||
case "香草期权":
|
||||
case "障碍期权":
|
||||
case "合成价差期权":
|
||||
case "累计期权":
|
||||
if (td.ParentTradeId == 0)
|
||||
{
|
||||
result = PS.Config.Is瑞达 && td.TradeType == "香草期权" ? td.ExerciseModeCn + td.OptionType + "期权" : td.ExerciseModeCn + td.TradeType.Replace("期权", "") + td.OptionType + "期权";
|
||||
}
|
||||
else
|
||||
{
|
||||
var tradelists = DbContextFactory.GetYLDbContext().trade.Where(x => x.id == td.ParentTradeId).FirstOrDefault();
|
||||
result = tradelists?.StructureType ?? tradelists?.TradeType ?? td.StructureType ?? td.TradeType;
|
||||
}
|
||||
break;
|
||||
case "现金流交易":
|
||||
result = td.TradeType;
|
||||
break;
|
||||
default:
|
||||
result = td.TradeType;
|
||||
switch (td.TradeType)
|
||||
{
|
||||
case "结构化交易":
|
||||
result = td.StructureType;
|
||||
break;
|
||||
case "凤凰期权":
|
||||
case ConsGlobal.TradeType.CashFlow:
|
||||
case ConsGlobal.TradeType.Forward:
|
||||
case ConsGlobal.TradeType.PayoffSwap:
|
||||
break;
|
||||
case "自定义交易":
|
||||
result = td.StructureIntroduction.TrimToNull() ?? td.StructureType.TrimToNull() ?? td.TradeType;
|
||||
break;
|
||||
case "气囊结构":
|
||||
case "区间累积期权":
|
||||
case "收益增强结构":
|
||||
result = td.ExerciseModeCn + td.TradeType;
|
||||
break;
|
||||
default:
|
||||
result = td.ExerciseModeCn + td.TradeType.Replace("期权", "") + td.OptionType + "期权";
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 雪球期权生成交易摘要
|
||||
/// </summary>
|
||||
public static IEnumerable<(string text, string value)> GetUnwindAbstractInfoItems_snowball(trade_cash tc, trade td, bool isUnwind)
|
||||
{
|
||||
var snowball = td.trade_snowball;
|
||||
if (snowball == null)
|
||||
{
|
||||
throw new ServiceException("雪球期权扩展信息不存在,无法生成交易摘要");
|
||||
}
|
||||
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
|
||||
var QuoteUnitString = " 元/" + (PS.Config.IsUseDisplayNotional ? underlying.QuoteUnitString : underlying.TradeUnitString);
|
||||
var IsUsePremiumRate = td.IsUsePremiumRate == true;
|
||||
var SpotPrice = underlying.UnderlyingInstrumentType == "CommodityFutures" ? td.SpotPrice : td.InitialSpotPrice;
|
||||
|
||||
var strikeFmt = td.IsMoneynessOption == "是"
|
||||
? new Func<double?, string>(d => OtcFormatExtensions.OtcFormat(d, OtcFormatFlag.percent))
|
||||
: new Func<double?, string>(d => OtcFormatExtensions.OtcFormatFlex(d, 2, 4));
|
||||
|
||||
|
||||
var premiumFmt = IsUsePremiumRate
|
||||
? new Func<double?, string>(d => OtcFormatExtensions.OtcFormat(d, OtcFormatFlag.premiumRateP))
|
||||
: new Func<double?, string>(d => OtcFormatExtensions.OtcFormat(d, OtcFormatFlag.tradeSinglePrice));
|
||||
|
||||
var tradeAmount = td.TradeAmount.OtcFormatNotional() + (td.UnderlyingInstrumentType == "Stock"
|
||||
? " 股" : " " + td.QuoteUnitSingle);
|
||||
|
||||
var list = new List<(string, string)>();
|
||||
|
||||
var action = tc.Action.Substring(5, 2);
|
||||
|
||||
if (PS.Config.Is厦门象屿)
|
||||
{
|
||||
list.Add(($"{action}信息", ""));
|
||||
}
|
||||
|
||||
list.AddRange(new[] {
|
||||
("交易编号", td.TradeNumber),
|
||||
("开仓日期", td.TradeDate.OtcFormatDate()),
|
||||
("开仓方向", td.ClientName),
|
||||
("#", td.BuySell == "买入" ? "卖出" : "买入"),
|
||||
("期权类型", GetTradeType(td)),
|
||||
("标的名称",td.UnderlyingAssetName),
|
||||
("标的代码",td.UnderlyingCode),
|
||||
("名义本金",OtcFormatExtensions.OtcFormat(td.StockEqvNotionalToShow, OtcFormatFlag.StockEqvNotional))
|
||||
});
|
||||
if (snowball.KORebate > 0)
|
||||
{
|
||||
list.Add((" 票息", snowball.KORebate.OtcFormatPercent()));
|
||||
}
|
||||
//var suffix = isUnwind ? " (平仓)" : "(行权)";
|
||||
var action_2 = $"({action})";
|
||||
list.Add(("期初价格", td.SpotPrice.OtcFormatUmPrice()));
|
||||
|
||||
if (!snowball.IsInitialKnockedIn)
|
||||
{
|
||||
list.Add(("敲入价格", strikeFmt(snowball.KIBarrier)));
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(("初始敲入", "是"));
|
||||
}
|
||||
list.Add(("敲出价格", strikeFmt(snowball.KOBarrier)));
|
||||
list.Add(("执行价格", strikeFmt(td.Strike)));
|
||||
list.Add(("到期日期", td.ExerciseDate.OtcFormatDate()));
|
||||
list.Add(("终止价格", tc.FinalPrice.OtcFormatUmPrice() + action_2));
|
||||
list.Add(("终止日期", tc.ValueDate.OtcFormatDate()));
|
||||
|
||||
var amount = tc.Amount * (valuedateBLL.SystemDate.UnwindAmountAngle == 1 ? -1 : EodOperationBase.GetSign(td.BuySell));
|
||||
list.Add(("结算金额", (amount).OtcFormatMoney() + "元"));
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 远期平仓摘要
|
||||
/// </summary>
|
||||
public static IEnumerable<(string text, string value)> GetUnwindAbstractInfoItems_Forward(trade_cash tc, trade td)
|
||||
{
|
||||
var snowball = td.trade_forward;
|
||||
|
||||
|
||||
if (snowball == null)
|
||||
{
|
||||
throw new ServiceException("远期扩展信息不存在,无法生成交易摘要");
|
||||
}
|
||||
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(td.UnderlyingCode);
|
||||
var QuoteUnitString = " 元/" + (PS.Config.IsUseDisplayNotional ? underlying.QuoteUnitString : underlying.TradeUnitString);
|
||||
var IsUsePremiumRate = td.IsUsePremiumRate == true;
|
||||
var strikeFmt = new Func<double?, string>(d => d.OtcFormatUmPrice(td.IsMoneynessOption == "是"));
|
||||
|
||||
var premiumFmt = IsUsePremiumRate
|
||||
? new Func<double?, string>(d => OtcFormatExtensions.OtcFormat(d, OtcFormatFlag.premiumRateP))
|
||||
: new Func<double?, string>(d => OtcFormatExtensions.OtcFormat(d, OtcFormatFlag.tradeSinglePrice));
|
||||
|
||||
var tradeAmount = td.TradeAmount.OtcFormatNotional() + (td.UnderlyingInstrumentType == "Stock"
|
||||
? " 股" : " " + td.QuoteUnitSingle);
|
||||
|
||||
var winloss = TradeCalcHelper.CalcWinLoss(tradeType: td.TradeType, buySell: td.BuySell, tradePrice: td.TradePrice ?? 0, tcUnwindPercent: tc.UnwindPercentRate ?? (tc.UnwindNotional / td.OriginalNotional) ?? 0, tcAmount: tc.Amount);
|
||||
|
||||
var list = new List<(string, string)>();
|
||||
if (PS.Config.Is厦门象屿)
|
||||
{
|
||||
list.Add(("平仓信息", ""));
|
||||
}
|
||||
var actualExerciseDate = td.ExerciseDate;
|
||||
if (td.MetaDic == null || td.MetaDic.Count == 0)
|
||||
{
|
||||
var exerciseDate = new TradeMetaService(OptUserInfo.SystemUser).GetTradeMeta(td.id, "ActualExerciseDate");
|
||||
if (!string.IsNullOrWhiteSpace(exerciseDate) && DateTime.TryParse(exerciseDate, out var tempDate))
|
||||
{
|
||||
actualExerciseDate = tempDate;
|
||||
}
|
||||
}
|
||||
list.AddRange(new[] {
|
||||
("交易编号", td.TradeNumber),
|
||||
("开仓日期", td.TradeDate.OtcFormatDate()),
|
||||
("开仓方向", td.ClientName),
|
||||
("#", td.BuySell == "买入" ? "卖出" : "买入"),
|
||||
("结构类型", (td.StructureType.TrimToNull()??td.TradeType) + (td.OptionType == "看涨" ? "多头" : "空头")),
|
||||
("标的代码",td.UnderlyingCode),
|
||||
("执行价格",td.Strike.OtcFormatUmPrice(td.IsMoneynessOption == "是")),
|
||||
("到期日期", actualExerciseDate.OtcFormatDate()),
|
||||
("平仓日期", tc.ValueDate.OtcFormatDate()),
|
||||
("标的价格", td.SpotPrice.OtcFormatUmPrice()),
|
||||
(new string(' ', 5),tc.FinalPrice.OtcFormatUmPrice() + "(平仓)"),
|
||||
("平仓数量",td.UnderlyingInstrumentType=="Stock"?tc.UnwindNotional.OtcFormatNotional()+"股":
|
||||
tc.UnwindTradeAmount.OtcFormatNotional(underlying.CountRatio,PS.Config.IsUseDisplayNotional)+ " " +(td.QuoteUnitSingle == "吨" && underlying.UnderlyingType == "鸡蛋" ? "半吨":td.QuoteUnitSingle)),
|
||||
("平仓总额", (-tc.Amount).OtcFormatMoney() + "元"), //客户角度,故为相反金额
|
||||
("实现盈亏",(-winloss).OtcFormatMoney() + " 元")
|
||||
});
|
||||
return list;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 现金流平仓摘要
|
||||
/// </summary>
|
||||
public static IEnumerable<(string text, string value)> GetUnwindAbstractInfoItems_cashflow(trade_cash tc, trade td)
|
||||
{
|
||||
var cashflow = td.trade_cashflow;
|
||||
if (cashflow == null)
|
||||
{
|
||||
throw new ServiceException("现金流扩展信息不存在,无法生成交易摘要");
|
||||
}
|
||||
|
||||
var list = new List<(string, string)>();
|
||||
if (PS.Config.Is厦门象屿)
|
||||
{
|
||||
list.Add(("平仓信息", ""));
|
||||
}
|
||||
//客户角度,故为相反金额
|
||||
var amount = tc.Amount * (valuedateBLL.SystemDate.UnwindAmountAngle == 1 ? -1 : EodOperationBase.GetSign(td.BuySell));
|
||||
list.AddRange(new[] {
|
||||
("交易编号", td.TradeNumber),
|
||||
("开仓日期", td.TradeDate.OtcFormatDate()),
|
||||
("开仓方向", td.ClientName),
|
||||
("#", td.BuySell == "买入" ? "卖出" : "买入"),
|
||||
("平仓日期", tc.ValueDate.OtcFormatDate()),
|
||||
("名义本金",(tc.UnwindPercentRate * td.OriginalStockEqvNotional).OtcFormatNotional() + "元"),
|
||||
("平仓总额", (amount).OtcFormatMoney() + "元"),
|
||||
});
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user