using Qdp.ComputeServiceV2.Data.CommonModels.TradeInfos;
using Qdp.Foundation.Implementations;
using Qdp.Pricing.Base.Utilities;
using System.Runtime.CompilerServices;
using YLErp.BLL;
using YLErp.BLL.Calculation;
using YLErp.QdpModule;
namespace YLErp.Modules.CalculationModule
{
///
/// 交易计算帮助类
///
public static class TradeCalcHelper
{
///
/// [交易员角度]根据交易方向判断了结金额是否需要加符号
/// 开仓费不适用 -- 开仓费是客户方向
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetBuySellSign(string buySell)
{
switch (buySell)
{
case "卖出":
case "融券卖出":
case "多头平仓":
case "空头开仓":
return -1;
default:
return 1;
}
}
///
/// [交易员角度]根据交易方向判断了结金额是否需要加符号
/// 开仓费不适用 -- 开仓费是客户方向
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int GetSign(string buySell)
{
return GetBuySellSign(buySell);
}
///
/// 远期计算(从交易员角度计算)
///
public static void CalcForwardValue(OtcTrade trade, double spotPrice, out double pv, out double pnl)
{
//1.结算报告,期权价格 / 单价: 现价 - 交割价格
//2.持仓市值: 期权价格* 持仓数量
//3.持仓盈亏: 持仓市值 - 持仓数量比率 * 开仓总费用
pv = pnl = 0;
if (trade.Notional <= 1e-7)
{
return;
}
var priceChange = 0d;
if (trade.OptionType == "看涨")
{
priceChange = spotPrice - (trade?.Strike ?? 0);
}
else if (trade.OptionType == "看跌")
{
priceChange = (trade?.Strike ?? 0) - spotPrice;
}
//以交易员角度
if (trade.BuySell == "卖出")
{
priceChange = -priceChange;
}
pv = priceChange * trade.Notional;
pnl = pv + (trade.OriginalNotional > 0 && trade.TradePrice >= 0 ? trade.TradePrice.Value * trade.Notional / trade.OriginalNotional.Value : 0);
}
///
/// 对冲交易 根据结构类型 买卖方向 看涨看跌 获取持仓long short
///
public static string GetHedgeLongShort(string TradeType, string BuySell)
{
switch (TradeType)
{
case "信用债":
case "商品期货":
case "场内期权":
return BuySell.Contains("多头") ? "long" : "short";
case "股票":
default: return "long";
}
}
///
/// 根据期权交易获取QDP Trade
///
public static TradeBase GetQdpTrade(trade tr, DateTime? valueDate = null, string fixings = null)
{
if (!valueDate.HasValue)
{
valueDate = valuedateBLL.ValueDate;
}
TradeBase tempTrade = null;
var sysRiskRate = valuedateBLL.RiskFreeRate / 100;
OptionTradeParamRequest getRequest()
{
return new OptionTradeParamRequest(sysRiskRate)
{
tradeId = tr.TradeNumber,
fixings = null,
hasNightMarket = false,
maturityShift = 0,
ParamOverride = null,
preciseTimeMode = false,
timeToMaturityDays = double.NaN,
volSurfaceNames = null
};
}
switch (tr.TradeType)
{
case "自定义交易":
{
tempTrade = new ManualTrade(tr.id.ToString(), new Date(tr.TradeDate.Value.Date),
new Date(tr.StartDate ?? valueDate.Value), new Date(tr.MaturityDate ?? valueDate.Value),
QdpConverter.ConvertTradeType(tr.BuySell), tr.Notional, 0);
break;
}
case "收益互换":
{
tempTrade = new SwapTrade(tr.id.ToString(), new Date(tr.TradeDate.Value.Date),
new Date(tr.StartDate ?? valueDate.Value), new Date(tr.MaturityDate ?? valueDate.Value),
QdpConverter.ConvertTradeType(tr.BuySell), tr.Notional, tr.SpotPrice ?? 0);
break;
}
case "亚式期权":
{
var request = getRequest();
request.fixings = fixings.TrimToNull() ?? AsianOptionFixingService.GetFixingString(valueDate.Value, tr);
tempTrade = QdpTradeBuilder.GetAsianOptionTrade(tr, tr.trade_asian_option, request);
break;
}
case "彩虹期权":
tempTrade = QdpTradeBuilder.GetRainbowOptionTrade(tr, tr.trade_rainbow_option, getRequest());
break;
case "合成价差期权":
tempTrade = QdpTradeBuilder.GetSSpreadOptionTrade(tr, getRequest());
break;
case "香草期权":
tempTrade = QdpTradeBuilder.GetVanillaOptionTrade(tr, getRequest(), false);
break;
case "Risky期权":
tempTrade = QdpTradeBuilder.GetVanillaOptionTrade(tr, getRequest(), false);
break;
case "障碍期权":
tempTrade = QdpTradeBuilder.GetBarrierOptionTrade(tr, tr.trade_barrier_option, getRequest());
break;
case "二元期权":
tempTrade = QdpTradeBuilder.GetBinaryOptionTrade(tr, tr.trade_binary_option, getRequest());
break;
case "双鲨期权":
tempTrade = QdpTradeBuilder.GetDoubleSharkFinOptionTrade(tr, tr.trade_double_sharkfin_option, getRequest());
break;
case "凤凰期权":
tempTrade = QdpTradeBuilder.GetAutocallOptionTrade(tr, tr.trade_autocall, getRequest());
break;
case "雪球期权":
tempTrade = QdpTradeBuilder.GetSnowballOptionTrade(tr, tr.trade_snowball, getRequest());
break;
case "区间累积期权":
tempTrade = QdpTradeBuilder.GetRangeAccrualTrade(tr, tr.trade_rangeaccrual, getRequest());
break;
case "气囊结构":
tempTrade = QdpTradeBuilder.GetAirbagOptionTrade(tr, tr.trade_airbag, getRequest());
break;
case "累计期权":
{
var req = getRequest();
req.happenedObservations = ObservationDataService.QueryDatas(tr.id, valueDate.Value);
tempTrade = QdpTradeBuilder.GetAccumulatorOptionTrade(tr, tr.trade_accumulator_option, req);
}
break;
case "收益增强结构":
tempTrade = QdpTradeBuilder.GetUnderlyingEnhanceTrade(tr, tr.trade_underlying_enhance, getRequest());
break;
case "现金流交易":
tempTrade = QdpTradeBuilder.GetCashFlowTrade(tr, tr.trade_cashflow, getRequest());
break;
}
return tempTrade;
}
///
/// 根据valuedate配置判断是否使用收盘价进行结算
///
public static bool UseClosePrice()
{
return ConsGlobal.SettlePriceMode.UseClosePrice(valuedateBLL.SystemDate.EodSettlePriceMode);
}
///
/// 根据valuedate配置获取收盘结算价类型
///
public static SettlementTypeEnum GetSettlementType()
{
return ConsGlobal.SettlePriceMode.GetSettlementType(valuedateBLL.SystemDate.EodSettlePriceMode);
}
///
///
///
public static string GetTradeStatus(trade trade, trade_cash tradeCash)
{
if (tradeCash.Action == "系统操作-平仓费" && (tradeCash.UnwindType == "部分平仓" || tradeCash.UnwindType == "全部平仓"))
{
return "已平仓";
}
if (tradeCash.Action == "系统操作-行权费" && tradeCash.ExerciseWay == "到期行权" && tradeCash.UnwindType == "到期")
{
return "已到期";
}
if ((tradeCash.Action == "系统操作-平仓费" && tradeCash.UnwindType == "部分行权") || tradeCash.Action == "系统操作-行权费")
{
return "已行权";
}
return trade.TradeStatus;
}
///
/// 以交易员角度计算盈亏
///
/// 交易方向
/// 交易总额
/// 平仓比例
/// 平仓收支
public static double CalcWinLoss(string tradeType, string buySell, double tradePrice, double tcUnwindPercent, double tcAmount)
{
int costSign = 1; //收入计为1,支出计为-1
if (tradeType != "远期")
{
switch (buySell)
{
case "卖出":
case "融券卖出":
case "多头平仓":
case "空头开仓": break;
default:
costSign = -1;
break;
}
}
return tcAmount + tradePrice * tcUnwindPercent * costSign;
}
///
/// 计算单笔交易或多笔交易实现盈亏
///
///
///
///
///
///
public static double CalcChildTradeSumWinLoss(trade td, trade_cash tc, bool IsUsePremiumRate = false, int CountRatio = 0)
{
using (var db = DbContextFactory.GetYLDbContext())
{
double TcTradePrice = 0;
if (td.IsGroup == 1)
{
var childTradeCashs = db.trade_cash.Where(x => x.ParentTradeCashId == tc.id).ToList();
var childTradeIds = childTradeCashs.Select(x => x.TradeId).Distinct().ToList();
var childTrades = db.trade.Where(x => childTradeIds.Contains(x.id)).ToList();
childTradeCashs.ForEach(x =>
{
var trade = childTrades.FirstOrDefault(y => y.id == x.TradeId);
TcTradePrice += (x.UnwindPercentRate * trade?.TradePrice * (trade?.BuySell == "买入" ? -1 : 1)) ?? 0;
});
return tc.Amount + TcTradePrice;
}
else
{
if (IsUsePremiumRate)
{
return (tc.Amount + (td.BuySell == "卖出" ? 1 : -1) * ((tc?.UnwindTradeAmount ?? 0) * CountRatio / td.OriginalNotional) * td.TradePrice) ?? 0;
}
return (tc.Amount + (td.BuySell == "卖出" ? 1 : -1) * (tc?.UnwindPercentRate ?? 0) * td?.TradePrice) ?? 0;
}
}
}
///
/// 计算TTM
///
public static double CalculateTTMDays(DateTime from, DateTime to, int varietyid, bool precisionOfMinute, DateTime? serverDateTime = null)
{
var dayCount = valuedateBLL.TradeDayCount.ToDayCountImpl();
var variety = DataCacheProvider.GetVarietyDataSource().GetData(varietyid);
if (serverDateTime == null)
{
serverDateTime = DateTime.Now;
}
return QdpHelper.CalculateTTMDays(from, to, valuedateBLL.ValueDate, serverDateTime.Value, dayCount, variety != null && variety.HasNightMarket, precisionOfMinute);
}
///
/// 计算TTM
///
public static double CalculateTTMDaysForXiangYu(DateTime from, DateTime to, int varietyid, bool precisionOfMinute, DateTime? serverDateTime = null)
{
var dayCount = valuedateBLL.TradeDayCount.ToDayCountImpl();
var variety = DataCacheProvider.GetVarietyDataSource().GetData(varietyid);
if (serverDateTime == null)
{
serverDateTime = DateTime.Now;
}
return QdpHelper.CalculateTTMDaysForXiangYu(from, to, valuedateBLL.ValueDate, serverDateTime.Value, dayCount, variety != null && variety.HasNightMarket, precisionOfMinute);
}
///
/// 传入OTC买卖方向判断是否买入方向
///
public static bool IsBuy(string buySell)
{
return buySell == "Buy" || buySell == "买入" || string.IsNullOrWhiteSpace(buySell);
}
///
/// 用于计算成交数量(虚拟),如果countRatio传入的是1,就可以用来计算成交份额
///
public static double GetTradeAmountV(OtcTradeBase trade, int? countRatio = null)
{
return InnerGetTradeAmountV(trade, null, countRatio);
}
///
/// 用于计算成交数量(虚拟),如果countRatio传入的是1,就可以用来计算成交份额
///
public static double GetTradeAmountV(OtcTradeBase trade, double notional, int? countRatio = null)
{
return InnerGetTradeAmountV(trade, notional, countRatio);
}
///
/// 用于计算成交数量(实际),如果countRatio传入的是1,就可以用来计算成交份额
///
public static double GetTradeAmount(OtcTradeBase trade, double notional, int? countRatio = null)
{
return InnerGetTradeAmount(trade, notional, countRatio);
}
///
///
///
private static double InnerGetTradeAmountV(OtcTradeBase trade, double? notional, int? countRatio)
{
if (trade is null)
{
throw new ArgumentNullException(nameof(trade));
}
var CountRatio = countRatio ?? trade.CountRatio ?? 0;
if (CountRatio < 1)
{
CountRatio = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode)?.CountRatio ?? 1;
}
if (trade.TradeType == "累计期权")
{
return (notional ?? trade.OriginalNotional ?? 0) / CountRatio;
}
if (!notional.HasValue)
{
var SpotPrice = trade.SpotPrice ?? 0;
if (Math.Abs(SpotPrice) > 0)
{
return (trade.OriginalStockEqvNotional ?? 0) / Math.Abs(SpotPrice) / CountRatio;
}
}
var annRate = (trade.ParticipationRate ?? 1) * (trade.AnnualizeFactor ?? 1);
if (annRate < 1e-8)
{
annRate = 1;
}
return (notional ?? trade.OriginalNotional ?? 0) / annRate / CountRatio;
}
///
///
///
private static double InnerGetTradeAmount(OtcTradeBase trade, double? notional, int? countRatio)
{
if (trade is null)
{
throw new ArgumentNullException(nameof(trade));
}
var CountRatio = countRatio ?? trade.CountRatio ?? 0;
if (CountRatio < 1)
{
CountRatio = DataCacheProvider.GetUnderlyingDataSource().GetData(trade.UnderlyingCode)?.CountRatio ?? 1;
}
if (trade.TradeType == "累计期权")
{
return (notional ?? trade.OriginalNotional ?? 0) / CountRatio;
}
if (!notional.HasValue)
{
var SpotPrice = trade.SpotPrice ?? 0;
if (Math.Abs(SpotPrice) > 0)
{
return (trade.OriginalStockEqvNotional ?? 0) / Math.Abs(SpotPrice) / CountRatio;
}
}
var annRate = (trade.ParticipationRate ?? 1) * (trade.AnnualizeFactor ?? 1);
if (annRate < 1e-8)
{
annRate = 1;
}
return (notional ?? trade.OriginalNotional ?? 0) * annRate / CountRatio;
}
}
}