Files
zszq-trs/YLErpDAL/Modules/CalculationModule/OptionTradeAnalysisService.cs

686 lines
31 KiB
C#

using Qdp.Foundation.Implementations;
using Qdp.Pricing.Base.Implementations;
using Qdp.Pricing.Base.Interfaces;
using Qdp.Pricing.Base.Utilities;
using Qdp.Pricing.Library.Common.Base;
using Qdp.Pricing.Library.Options.Products.Accumulator;
using Qdp.Pricing.Library.Options.Products.Airbag;
using Qdp.Pricing.Library.Options.Products.Asian;
using Qdp.Pricing.Library.Options.Products.AsianSyntheticSpread;
using Qdp.Pricing.Library.Options.Products.Autocall.Phoenix;
using Qdp.Pricing.Library.Options.Products.Autocall.Snowball;
using Qdp.Pricing.Library.Options.Products.Barrier;
using Qdp.Pricing.Library.Options.Products.Binary;
using Qdp.Pricing.Library.Options.Products.DoubleSharkFin;
using Qdp.Pricing.Library.Options.Products.PayoffEnhance;
using Qdp.Pricing.Library.Options.Products.Rainbow;
using Qdp.Pricing.Library.Options.Products.RangeAccrual;
using Qdp.Pricing.Library.Options.Products.Spread;
using Qdp.Pricing.Library.Options.Products.SyntheticSpread;
using Qdp.Pricing.Library.Options.Products.Vanilla;
using YLErp.BLL;
using YLErp.BLL.Calculation.V2;
using YLErp.Modules.TradeModule;
using YLErp.Modules.VolatilityModule;
using YLErp.QdpModule;
namespace YLErp.Modules.CalculationModule
{
public class OptionTradeAnalysisService : YLBaseService
{
public OptionTradeAnalysisService(OptUserInfo userInfo) : base(userInfo)
{
}
/// <summary>
/// 为一组期权交易计算到期时在不同价格条件下的总体payoff情况
/// </summary>
/// <param name="optionTrades"></param>
/// <returns></returns>
public List<CurvePoint> GetTradesPayoffLine(IEnumerable<OtcOptionTradeFull> optionTrades)
{
if (optionTrades == null)
{
return null;
}
var curvePoints = new List<CurvePoint>();
var keyPricePoints = new List<double>();
if (optionTrades.Count(t => t.TradeType == "雪球期权" || t.TradeType == "凤凰期权") > 0)
{
throw new Exception($"暂时不支持Autocall的分析");
}
var underlyingIds = optionTrades.Select(n => n.UnderlyingId).ToHashSet();
if (underlyingIds.Count > 1)
{
throw new Exception($"待分析的组合交易需要有相同的标的资产");
}
var underlying = DbContext.underlying_manager.AsNoTracking().FirstOrDefault(n => underlyingIds.Contains(n.id));
if (underlying == null)
{
throw new Exception($"找不到标的资产{optionTrades.First().UnderlyingCode}的信息,id为{optionTrades.First().UnderlyingId}");
}
var options = new List<OptionBase>();
foreach (var otcTrade in optionTrades)
{
var trade = TradeConverter.ConvertOptionTrade(otcTrade);
if (otcTrade.TradeType == "Risky期权")
{
var _options = GetToQdpOptionRisk(trade, underlying);
if (_options != null)
{
options.AddRange(_options);
}
}
else
{
var option = ToQdpOption(trade, underlying);
if (option != null)
{
options.Add(option);
}
}
var points = GetKeyPoints(trade);
if (points != null)
{
keyPricePoints.AddRange(points);
}
}
keyPricePoints = keyPricePoints.Distinct().ToList();
keyPricePoints.Sort();
keyPricePoints.Insert(0, keyPricePoints.First() * 0.8);
keyPricePoints.Add(keyPricePoints.Last() * 1.2);
var prices = new double[] { 0.0 };
foreach (var price in keyPricePoints)
{
prices[0] = price;
curvePoints.Add(new CurvePoint()
{
X = price,
Y = options.Sum(x =>
{
if (x is BarrierOption barrier)
{
//障碍期权在GetPayoff方法中会更改BarrierStatus值,所以需要重置
barrier.BarrierStatus = Qdp.Pricing.Base.Enums.BarrierStatus.Monitoring;
}
return x.GetPayoff(prices)[0].PaymentAmount;
})
});
}
return curvePoints;
}
/// <summary>
/// 为一组期权交易计算不同价格条件下的Pv
/// </summary>
public List<CurvePoint> GetTradesPvLine(IEnumerable<OtcOptionTradeFull> optionTrades)
{
if (optionTrades == null)
{
return null;
}
if (!optionTrades.Any())
{
return new List<CurvePoint>(0);
}
var curvePoints = new List<CurvePoint>();
var keyPricePoints = new List<double>();
if (optionTrades.Count(t => t.TradeType == "雪球期权" || t.TradeType == "凤凰期权") > 0)
{
throw new Exception($"暂时不支持Autocall的分析");
}
var underlyingCount = optionTrades.Select(n => n.UnderlyingCode?.ToLowerInvariant()).Distinct().Count();
if (underlyingCount > 1)
{
throw new Exception($"待分析的组合交易需要有相同的标的资产");
}
var trades = new List<trade>();
foreach (var otcTrade in optionTrades)
{
var trade = TradeConverter.ConvertOptionTrade(otcTrade);
if (trade != null)
{
trades.Add(trade);
}
var points = GetKeyPoints(trade);
if (points != null)
{
keyPricePoints.AddRange(points);
}
}
return GetTradesPvLineForKeyPoints(optionTrades.First().TradeDate.Value, trades, keyPricePoints);
}
private List<CurvePoint> GetTradesPvLineForKeyPoints(DateTime valueDate, IEnumerable<trade> trades, List<double> keyPoints)
{
var curvePoints = new List<CurvePoint>();
if (trades == null || trades.Count() == 0)
{
return curvePoints;
}
var startPrice = keyPoints.Min() > 0 ? keyPoints.Min() * 0.8 : keyPoints.Min() * 1.2;
var endPrice = keyPoints.Min() > 0 ? keyPoints.Max() * 1.2 : keyPoints.Max() * 0.8;
var step = (endPrice - startPrice) / 20.0;
var price = startPrice;
var calcReq = new OptionValueCalcRequest(valuedateBLL.SysRiskFreeRate())
{
correlations = null,
engineName = null,
maturityShift = 0,
ParamOverride = null,
preciseTimeMode = false,
pricingRequest = PricingRequest.Pv
};
while (price < endPrice + step)
{
var pv = 0.0;
foreach (var trade in trades)
{
//场内期权交易不会有开仓波动率,因此根据其交易价格计算出隐含波动率
if (trade.TradeType == "场内期权" && !trade.TradeOpenVolatility.HasValue)
{
trade.VolType = "交易";
trade.TradeOpenVolatility = VolatilityHelper.GetImpliedVol(trade.TradeDate ?? valuedateBLL.ValueDate, trade, trade.TTMDays, trade.SpotPrice ?? 0, true);
}
if (!PS.Config.IsTradeVol && !trade.TradeOpenVolatility.HasValue)
{
trade.TradeOpenVolatility = trade.Vol;
}
if (!trade.TradeOpenVolatility.HasValue || double.IsNaN(trade.TradeOpenVolatility.Value))
{
throw new Exception("无法获取开仓波动率");
}
calcReq.spotPrices = new[] { price };
calcReq.vols = new[] { trade.TradeOpenVolatility.Value };
var result = OptionCalculatorV2.GetOptionValueResult(valueDate, trade, calcReq, out _);
if (double.IsNaN(result.Pv))
{
throw new Exception($"计算此交易失败:{trade.UnderlyingCode},{trade.TradeType}");
}
pv += result.Pv;
}
curvePoints.Add(new CurvePoint()
{
X = price,
Y = pv
});
price += step;
}
return curvePoints;
}
public List<CurvePoint> GetTradesPvLine2(int tradeId)
{
var trade = DbContext.trade.FirstOrDefault(t => t.id == tradeId);
if (trade == null)
{
return null;
}
List<trade> trades;
if (trade.TradeType == "结构化交易")
{
trades = DbContext.trade.Where(t => t.ParentTradeId == trade.id).ToList();
}
else
{
trades = new List<trade> { trade };
}
var tradebll = new tradeBLL();
trades.ForEach(t => tradeBLL.SetFieldsByTradeType(t));
return GetTradesPvLine2(valuedateBLL.ValueDate, trades);
}
private List<CurvePoint> GetTradesPvLine2(DateTime valueDate, List<trade> optionTrades)
{
if (optionTrades == null)
{
return null;
}
if (optionTrades.Count(t => t.TradeType == "雪球期权" || t.TradeType == "凤凰期权") > 0)
{
throw new Exception($"暂时不支持Autocall的分析");
}
var underlyingCount = optionTrades.Select(n => n.UnderlyingCode.ToLowerInvariant()).Distinct().Count();
if (underlyingCount > 1)
{
throw new Exception($"待分析的组合交易需要有相同的标的资产");
}
var keyPricePoints = new List<double>();
optionTrades.ForEach(t =>
{
keyPricePoints.AddRange(GetKeyPoints(t));
});
return GetTradesPvLineForKeyPoints(valueDate, optionTrades, keyPricePoints);
}
/// <summary>
/// 计算交易在一半ttm时候的Pv曲线
/// </summary>
public List<CurvePoint> GetTradesHalflifePvLine(IEnumerable<OtcOptionTradeFull> optionTrades)
{
var dayCount = valuedateBLL.TradeDayCount.ToDayCountImpl();
foreach (var trade in optionTrades)
{
trade.ExerciseDate = AdjustToHalfLifeMaturity(dayCount, trade.TradeDate, trade.ExerciseDate);
trade.TTMDays = double.NaN;
}
return GetTradesPvLine(optionTrades);
}
/// <summary>
/// 返回当前、一半ttm、以及在到期时的Pv曲线
/// </summary>
/// <returns></returns>
public List<List<CurvePoint>> GetTradePvLifeLine(IEnumerable<OtcOptionTradeFull> optionTrades)
{
var results = new List<List<CurvePoint>>();
var pvLine = GetTradesPvLine(optionTrades);
results.Add(pvLine);
var payoffPoints = GetTradesPayoffLine(optionTrades);
//按Pv曲线的X点对齐
//int start = -1, end = 0;
//var payoffLine = new List<CurvePoint>();
//for (var i = 0; i < pvLine.Count; ++i)
//{
// if (pvLine[i].X == payoffPoints[end].X)
// {
// payoffLine.Add(payoffPoints[end]);
// ++start;
// ++end;
// }
// else
// {
// payoffLine.Add(new CurvePoint() { X = pvLine[i].X, Y = simpleInterpolate(payoffPoints[start].X, payoffPoints[end].X, payoffPoints[start].Y, payoffPoints[end].Y, pvLine[i].X) });
// }
//}
results.Add(payoffPoints);
results.Add(GetTradesHalflifePvLine(optionTrades));
return results;
}
private DateTime? AdjustToHalfLifeMaturity(IDayCount dayCount, DateTime? tradeDate, DateTime? maturityDate)
{
var qdpStart = new Date(tradeDate.Value);
var qdpEnd = new Date(maturityDate.Value);
var half = dayCount.CalcDayCountFraction(qdpStart, qdpEnd) / 2.0;
qdpEnd = dayCount.CalcEndDateFromDayCountFraction(qdpStart, half, null, null);
return qdpEnd.DateTime;
}
/// <summary>
/// 为一组期权交易计算随时间变化的希腊字母变化
/// </summary>
/// <param name="optionTrades"></param>
/// <returns></returns>
public Dictionary<string, List<CurvePoint>> GetTradesGreeksForLifetime(IEnumerable<OtcOptionTradeFull> optionTrades)
{
if (optionTrades == null)
{
return null;
}
var curvePoints = new List<CurvePoint>();
if (optionTrades.Count(t => t.TradeType == "雪球期权" || t.TradeType == "凤凰期权") > 0)
{
throw new Exception($"暂时不支持Autocall的分析");
}
var underlyingIds = optionTrades.Select(n => n.UnderlyingId).ToHashSet();
if (underlyingIds.Count > 1)
{
throw new Exception($"待分析的组合交易需要有相同的标的资产");
}
var underlying = DbContext.underlying_manager.AsNoTracking().FirstOrDefault(n => underlyingIds.Contains(n.id));
if (underlying == null)
{
throw new Exception($"找不到标的资产{optionTrades.First().UnderlyingCode}的信息,id为{optionTrades.First().UnderlyingId}");
}
var options = new List<OptionBase>();
var trades = new List<trade>();
foreach (var otcTrade in optionTrades)
{
var trade = TradeConverter.ConvertOptionTrade(otcTrade);
if (trade != null)
{
trades.Add(trade);
}
}
var minStart = trades.Min(t => t.TradeDate.Value);
//避开最后一天的计算,在到期日当天会出现一些跟时间相关的结果,会混淆曲线的整体趋势
var maxMaturity = CalendarImpl.Get("chn").PrevBizDay(new Date(trades.Max(t => t.ExerciseDate.Value)));
var valueDates = CalendarImpl.Get("chn").BizDaysBetweenDatesInclEndDay(new Date(minStart), new Date(maxMaturity));
var userId = Guid.NewGuid().ToString();
var results = new Dictionary<string, List<CurvePoint>>();
results["Pv"] = new List<CurvePoint>();
results["Delta"] = new List<CurvePoint>();
results["Gamma"] = new List<CurvePoint>();
results["Vega"] = new List<CurvePoint>();
results["Theta"] = new List<CurvePoint>();
for (var i = 0; i < valueDates.Count; ++i)
{
double pv = 0.0, delta = 0.0, gamma = 0.0, vega = 0.0, theta = 0.0;
foreach (var trade in trades)
{
trade.TradeDate = valueDates[i].DateTime;
trade.TTMDays = double.NaN;
underlying.QuotationDate = trade.TradeDate;
if (!PS.Config.IsTradeVol && !trade.TradeOpenVolatility.HasValue)
{
trade.TradeOpenVolatility = trade.Vol;
}
if (!trade.TradeOpenVolatility.HasValue || double.IsNaN(trade.TradeOpenVolatility.Value))
{
throw new Exception("无法获取开仓波动率");
}
var result = ValueCalculator.GetOptionValueResultV2(
userId,
underlying,
trade,
new double[] { trade.TradeOpenVolatility.Value },
new double[] { trade.SpotPrice.Value },
request: QdpPricingRequest.BASIC_GREEKS);
if (double.IsNaN(result.Pv))
{
throw new Exception($"计算此交易失败:{trade.UnderlyingCode},{trade.TradeType}");
}
pv += result.Pv;
delta += result.Delta;
gamma += result.Gamma;
vega += result.Vega;
theta += result.Theta;
}
results["Pv"].Add(new CurvePoint() { X = i, Y = pv });
results["Delta"].Add(new CurvePoint() { X = i, Y = delta });
results["Gamma"].Add(new CurvePoint() { X = i, Y = gamma });
results["Vega"].Add(new CurvePoint() { X = i, Y = vega });
results["Theta"].Add(new CurvePoint() { X = i, Y = theta });
}
return results;
}
/// <summary>
/// 获得一笔期权影响payoff的价格点,如行权价、障碍价格等
/// </summary>
/// <param name="trade"></param>
/// <returns></returns>
private IEnumerable<double> GetKeyPoints(trade trade)
{
switch (trade.TradeType)
{
case "香草期权":
case "场内期权":
case "亚式期权":
case "彩虹期权":
case "合成价差期权":
case "亚式合成价差期权":
case "收益增强结构":
case "区间累积期权":
case "价差期权":
case "凤凰期权":
case "雪球期权":
case "气囊结构":
return new double[] {
trade.IsMoneynessOptionData ? trade.Strike.Value * trade.SpotPrice.Value : trade.Strike.Value
};
case "累计期权":
if (trade.trade_accumulator_option.AccumulatorStructureType == AccumulatorStructureTypeEnum.Segmented)
{
return new double[] {
trade.IsMoneynessOptionData ? trade.Strike.Value * trade.SpotPrice.Value : trade.Strike.Value,
trade.IsMoneynessOptionData ? trade.trade_accumulator_option.Strike2.Value * trade.SpotPrice.Value : trade.trade_accumulator_option.Strike2.Value,
trade.IsMoneynessOptionData ? trade.trade_accumulator_option.Strike3.Value * trade.SpotPrice.Value : trade.trade_accumulator_option.Strike3.Value,
};
}
else
{
return new double[] {
trade.IsMoneynessOptionData ? trade.Strike.Value * trade.SpotPrice.Value : trade.Strike.Value
};
}
case "障碍期权":
if (trade.trade_barrier_option.BarrierTypeEn.StartsWith("Double"))
{
return new double[] {
trade.IsMoneynessOptionData ? trade.Strike.Value * trade.SpotPrice.Value : trade.Strike.Value,
trade.IsMoneynessOptionData ? trade.trade_barrier_option.BarrierPrice.Value* trade.SpotPrice.Value : trade.trade_barrier_option.BarrierPrice.Value,
trade.IsMoneynessOptionData ? trade.trade_barrier_option.BarrierPrice.Value* trade.SpotPrice.Value + 0.01 : trade.trade_barrier_option.BarrierPrice.Value + 0.01,
trade.IsMoneynessOptionData ? trade.trade_barrier_option.UpperBarrierPrice.Value * trade.SpotPrice.Value : trade.trade_barrier_option.UpperBarrierPrice.Value,
trade.IsMoneynessOptionData ? trade.trade_barrier_option.UpperBarrierPrice.Value * trade.SpotPrice.Value - 0.01 : trade.trade_barrier_option.UpperBarrierPrice.Value - 0.01
};
}
else
{
if (trade.trade_barrier_option.BarrierTypeEn.StartsWith("Up"))
{
return new double[] {
trade.IsMoneynessOptionData ? trade.Strike.Value * trade.SpotPrice.Value : trade.Strike.Value,
trade.IsMoneynessOptionData ? trade.trade_barrier_option.BarrierPrice.Value * trade.SpotPrice.Value : trade.trade_barrier_option.BarrierPrice.Value,
trade.IsMoneynessOptionData ? trade.trade_barrier_option.BarrierPrice.Value * trade.SpotPrice.Value - 0.01 : trade.trade_barrier_option.BarrierPrice.Value - 0.01
};
}
else
{
return new double[] {
trade.IsMoneynessOptionData ? trade.Strike.Value * trade.SpotPrice.Value : trade.Strike.Value,
trade.IsMoneynessOptionData ? trade.trade_barrier_option.BarrierPrice.Value * trade.SpotPrice.Value : trade.trade_barrier_option.BarrierPrice.Value,
trade.IsMoneynessOptionData ? trade.trade_barrier_option.BarrierPrice.Value * trade.SpotPrice.Value + 0.01 : trade.trade_barrier_option.BarrierPrice.Value + 0.01
};
}
}
case "二元期权":
if (trade.ExerciseMode == "American" && trade.trade_binary_option.PayoffType.StartsWith("Double"))
{
var low = trade.IsMoneynessOptionData ? trade.Strike.Value * trade.SpotPrice.Value : trade.Strike.Value;
var high = trade.IsMoneynessOptionData ? trade.trade_binary_option.UpperBarrier.Value * trade.SpotPrice.Value : trade.trade_binary_option.UpperBarrier.Value;
return new double[] {
low - 0.01,
low,
low + 0.01,
high - 0.01,
high,
high + 0.01
};
}
else
{
var low = trade.IsMoneynessOptionData ? trade.Strike.Value * trade.SpotPrice.Value : trade.Strike.Value;
return new double[] {
low - 0.01,
low,
low + 0.01
};
}
case "双鲨期权":
return new double[] {
trade.IsMoneynessOptionData ? trade.Strike.Value * trade.SpotPrice.Value : trade.Strike.Value,
trade.IsMoneynessOptionData ? trade.trade_double_sharkfin_option.StrikeHigh.Value * trade.SpotPrice.Value : trade.trade_double_sharkfin_option.StrikeHigh.Value,
trade.IsMoneynessOptionData ? trade.trade_double_sharkfin_option.BarrierHigh * trade.SpotPrice.Value : trade.trade_double_sharkfin_option.BarrierHigh,
trade.IsMoneynessOptionData ? trade.trade_double_sharkfin_option.BarrierHigh * trade.SpotPrice.Value - 0.01 : trade.trade_double_sharkfin_option.BarrierHigh - 0.01,
trade.IsMoneynessOptionData ? trade.trade_double_sharkfin_option.BarrierLow * trade.SpotPrice.Value : trade.trade_double_sharkfin_option.BarrierLow,
trade.IsMoneynessOptionData ? trade.trade_double_sharkfin_option.BarrierLow * trade.SpotPrice.Value + 0.01 : trade.trade_double_sharkfin_option.BarrierLow + 0.01,
};
case "Risky期权":
return new double[] {
trade.IsMoneynessOptionData ? trade.trade_risky_option.Strike1.Value * trade.SpotPrice.Value : trade.trade_risky_option.Strike1.Value,
trade.IsMoneynessOptionData ? trade.trade_risky_option.Strike2.Value * trade.SpotPrice.Value : trade.trade_risky_option.Strike2.Value,
trade.IsMoneynessOptionData ? trade.trade_risky_option.Strike3.Value * trade.SpotPrice.Value : trade.trade_risky_option.Strike3.Value,
};
default:
return null;
}
}
/// <summary>
/// 将trade对象转换为Qdp对应的期权类型
/// </summary>
private OptionBase ToQdpOption(trade trade, underlying_manager underlying)
{
underlying = underlying.Clone();
underlying.UnderlyingInstrumentType = ConsGlobal.InstrumentType.ConvertCalcType(underlying.UnderlyingInstrumentType,true);
switch (trade.TradeType)
{
case "香草期权":
return QdpTradeBuilder.GetVanillaOptionTrade(trade, null, false)?.Instrument as VanillaOption;
case "场内期权":
return QdpTradeBuilder.GetVanillaOptionTrade(trade, null, true)?.Instrument as VanillaOption;
case "障碍期权":
return QdpTradeBuilder.GetBarrierOptionTrade(trade, trade.trade_barrier_option, null)?.Instrument as BarrierOption;
case "亚式期权":
return QdpTradeBuilder.GetAsianOptionTrade(trade, trade.trade_asian_option, null)?.Instrument as AsianOption;
case "二元期权":
return QdpTradeBuilder.GetBinaryOptionTrade(trade, trade.trade_binary_option, null)?.Instrument as BinaryOption;
case "彩虹期权":
return QdpTradeBuilder.GetRainbowOptionTrade(trade, trade.trade_rainbow_option, null)?.Instrument as RainbowOption;
case "价差期权":
return QdpTradeBuilder.GetSpreadOptionTrade(trade, trade.trade_spread_option, null, null)?.Instrument as SpreadOption;
case "合成价差期权":
return QdpTradeBuilder.GetSSpreadOptionTrade(trade)?.Instrument as SyntheticNormalSpreadOption;
case "亚式合成价差期权":
return QdpTradeBuilder.GetAsianSSpreadOptionTrade(trade, trade.trade_asian_option, null)?.Instrument as AsianSyntheticNormalSpreadOption;
case "双鲨期权":
return QdpTradeBuilder.GetDoubleSharkFinOptionTrade(trade, trade.trade_double_sharkfin_option, null)?.Instrument as DoubleSharkFinOption;
case "凤凰期权":
return QdpTradeBuilder.GetAutocallOptionTrade(trade, trade.trade_autocall)?.Instrument as AutoCall;
case "雪球期权":
return QdpTradeBuilder.GetSnowballOptionTrade(trade, trade.trade_snowball)?.Instrument as SimpleSnowball;
case "区间累积期权":
return QdpTradeBuilder.GetRangeAccrualTrade(trade, trade.trade_rangeaccrual, null)?.Instrument as RangeAccrual;
case "累积期权":
case "累计期权":
return QdpTradeBuilder.GetAccumulatorOptionTrade(trade, trade.trade_accumulator_option, null)?.Instrument as AccumulatorOption;
case "气囊结构":
return QdpTradeBuilder.GetAirbagOptionTrade(trade, trade.trade_airbag, null)?.Instrument as Airbag;
case "收益增强结构":
return QdpTradeBuilder.GetUnderlyingEnhanceTrade(trade, trade.trade_underlying_enhance, null)?.Instrument as UnderlyingPayoffEnhance;
case "Risky期权":
return QdpTradeBuilder.GetVanillaOptionTrade(trade, null, false)?.Instrument as VanillaOption;
default:
return null;
}
}
public List<OptionBase> GetToQdpOptionRisk(trade trade, underlying_manager underlying)
{
var options = new List<OptionBase>();
var tradeclone = trade.Clone();
tradeclone.TradeAmount = tradeclone.TradeAmount = TradeCalcHelper.GetTradeAmountV(trade, trade.TradeAmount, 1);
tradeclone.Notional = tradeclone.Notional = TradeCalcHelper.GetTradeAmountV(trade, trade.Notional, underlying.CountRatio);
var td1 = tradeclone.Clone();
if (trade.trade_risky_option.ParticipationRate1 != 0)
{
td1.Strike = trade.trade_risky_option.Strike1;
td1.ParticipationRate = trade.trade_risky_option.ParticipationRate1;
td1.TradeAmount = TradeCalcHelper.GetTradeAmount(td1, td1.TradeAmount, 1);
td1.Notional = TradeCalcHelper.GetTradeAmount(td1, td1.Notional, underlying.CountRatio);
td1.OptionType = "看跌";
td1.BuySell = trade.BuySell == "买入" ? "卖出" : "买入";
var option1 = ToQdpOption(td1, underlying);
if (option1 != null)
{
options.Add(option1);
}
}
var td2 = tradeclone.Clone();
if (trade.trade_risky_option.ParticipationRate2 != 0)
{
td2.Strike = trade.trade_risky_option.Strike2;
td2.ParticipationRate = trade.trade_risky_option.ParticipationRate2;
td2.TradeAmount = TradeCalcHelper.GetTradeAmount(td2, td2.TradeAmount, 1);
td2.Notional = TradeCalcHelper.GetTradeAmount(td2, td2.Notional, underlying.CountRatio);
var option2 = ToQdpOption(td2, underlying);
if (option2 != null)
{
options.Add(option2);
}
}
var td3 = tradeclone.Clone();
//decimal 为了解决精度问题: 0.2-0.3=0.0999999999
var participationRate3 = (decimal)trade.trade_risky_option.ParticipationRate3 - (decimal)trade.trade_risky_option.ParticipationRate2;
if (participationRate3 != 0)
{
td3.Strike = trade.trade_risky_option.Strike3;
td3.ParticipationRate = (double?)Math.Abs(participationRate3);
td3.TradeAmount = TradeCalcHelper.GetTradeAmount(td3, td3.TradeAmount, 1);
td3.Notional = TradeCalcHelper.GetTradeAmount(td3, td3.Notional, underlying.CountRatio);
if (participationRate3 < 0)
{
td3.BuySell = trade.BuySell == "买入" ? "卖出" : "买入";
}
var option3 = ToQdpOption(td3, underlying);
if (option3 != null)
{
options.Add(option3);
}
}
return options;
}
}
public class CurvePoint
{
public double X { get; set; }
public double Y { get; set; }
}
}