545 lines
25 KiB
C#
545 lines
25 KiB
C#
using YLErp.BLL;
|
|
using YLErp.BLL.Calculation;
|
|
using YLErp.BLL.Calculation.V2;
|
|
using YLErp.BLL.Calculation.V2.Parameter;
|
|
using YLErp.Commons;
|
|
using YLErp.Model;
|
|
using YLErp.Modules.CalculationModule;
|
|
using YLErp.Modules.ClientModule;
|
|
using YLErp.Modules.VolatilityModule;
|
|
using YLErp.QdpModule;
|
|
|
|
namespace YLErp.Modules.TQuoteModule
|
|
{
|
|
/// <summary>
|
|
///
|
|
/// </summary>
|
|
public class TQuoteService : YLBaseService
|
|
{
|
|
public TQuoteService(OptUserInfo optUser) : base(optUser)
|
|
{
|
|
}
|
|
|
|
public TQuoteResult TQuoteWithCustomizedVol(TQuoteWithCustomizedVolRequest request)
|
|
{
|
|
if (request == null || request.Records == null)
|
|
{
|
|
return new TQuoteResult();
|
|
}
|
|
|
|
var valueDate = CalculatorHelper.RealtimeQuoteValueDate();
|
|
var valueDateStr = valueDate.ToString("yyyy-MM-dd");
|
|
|
|
underlying_manager underlying = null;
|
|
Variety variety = null;
|
|
using (var db = new YLContext())
|
|
{
|
|
underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(request.UnderlyingCode);
|
|
variety = db.variety.FirstOrDefault(x => x.VarietyCode != null && x.id == underlying.UnderlyingTypeId);
|
|
}
|
|
|
|
if (underlying == null)
|
|
{
|
|
return new TQuoteResult();
|
|
}
|
|
|
|
var qdpMarketId = Guid.NewGuid().ToString();
|
|
var marketProxy = QdpMarketManager.Instance.GetPrebuiltMarketProxy(qdpMarketId);
|
|
|
|
//使用全局的DiscountCurve以提高计算效率
|
|
var discountCurveName = Guid.NewGuid().ToString();
|
|
var discountCurve = CalculatorHelper.CreateConstantRiskFreeCurve(discountCurveName, valuedateBLL.RiskFreeRate / 100.0);
|
|
marketProxy.AddYieldCurve(discountCurveName, valueDateStr, discountCurve);
|
|
|
|
var tQuoteResult = new TQuoteResult
|
|
{
|
|
quotaList = new List<TQuoteRecord>()
|
|
};
|
|
|
|
//根据用户设置的bid/ask天数调整规则来分别调整到期日
|
|
//TODO: bidMaturityShift和askMaturityShift应该从某数据库表读取
|
|
var bidMaturityShift = 0;
|
|
var askMaturityShift = 0;
|
|
var otherInfo = "";
|
|
var client_param = ClientPricingParamService.GetPricingParam(valueDate.Date, Convert.ToDateTime(request.MaturityDate).Date);
|
|
if (client_param != null)
|
|
{
|
|
askMaturityShift = client_param.ask_tuning_day ?? 0;
|
|
bidMaturityShift = client_param.bid_tuning_day ?? 0;
|
|
otherInfo = client_param.ToJson();//$"ask到期日偏离{askMaturityShift}天,bid到期日偏离{bidMaturityShift}天";
|
|
}
|
|
|
|
var dayCount = CalculatorHelper.GetTradeDayCount();
|
|
var bidMaturityDate = QdpCalendarHelper.ShiftDate(request.MaturityDate, dayCount, bidMaturityShift);
|
|
var askMaturityDate = QdpCalendarHelper.ShiftDate(request.MaturityDate, dayCount, askMaturityShift);
|
|
var hasNightMarket = (variety?.HasNightMarket) ?? false;
|
|
|
|
var trade = new trade()
|
|
{
|
|
TradeType = "香草期权",
|
|
TradeDate = valueDate,
|
|
MaturityDate = DateTime.Parse(bidMaturityDate),
|
|
ExerciseDate = DateTime.Parse(bidMaturityDate),
|
|
OptionType = "看涨",
|
|
ExerciseMode = "European",
|
|
BuySell = "Buy",
|
|
Notional = 1,
|
|
UnderlyingCode = request.UnderlyingCode,
|
|
UnderlyingInstrumentType = underlying.UnderlyingInstrumentType
|
|
};
|
|
|
|
var parameter = new VanillaOptionParameter()
|
|
{
|
|
ValueDate = valueDate,
|
|
DiscountCurveName = discountCurveName,
|
|
SpotPrices = new Dictionary<string, double> { { underlying.UnderlyingCode, request.SpotPrice } },
|
|
HasNightMarket = hasNightMarket,
|
|
PreciseTimeMode = true
|
|
};
|
|
|
|
foreach (var record in request.Records)
|
|
{
|
|
trade.OptionType = "看涨";
|
|
trade.Strike = record.Strike;
|
|
parameter.Volatility = record.CallBidVol;
|
|
var callBidResult = ValueCalculator.CalculateTradeValue(qdpMarketId, trade, underlying, parameter);
|
|
|
|
trade.OptionType = "看跌";
|
|
trade.Strike = record.Strike;
|
|
parameter.Volatility = record.PutBidVol;
|
|
var putBidResult = ValueCalculator.CalculateTradeValue(qdpMarketId, trade, underlying, parameter);
|
|
|
|
trade.OptionType = "看涨";
|
|
trade.Strike = record.Strike;
|
|
parameter.Volatility = record.CallAskVol;
|
|
var callAskResult = ValueCalculator.CalculateTradeValue(qdpMarketId, trade, underlying, parameter);
|
|
|
|
trade.OptionType = "看跌";
|
|
trade.Strike = record.Strike;
|
|
parameter.Volatility = record.PutAskVol;
|
|
var putAskResult = ValueCalculator.CalculateTradeValue(qdpMarketId, trade, underlying, parameter);
|
|
|
|
tQuoteResult.quotaList.Add(new TQuoteRecord()
|
|
{
|
|
Strike = record.Strike,
|
|
CallBidPrice = callBidResult.Pv,
|
|
CallBidPricePercent = underlying.Price.HasValue ? callBidResult.Pv / underlying.Price.Value : 0.0,
|
|
CallBidVol = callBidResult.Vol,
|
|
|
|
PutBidPrice = putBidResult.Pv,
|
|
PutBidPricePercent = underlying.Price.HasValue ? putBidResult.Pv / underlying.Price.Value : 0.0,
|
|
PutBidVol = putBidResult.Vol,
|
|
|
|
CallAskPrice = callAskResult.Pv,
|
|
CallAskPricePercent = underlying.Price.HasValue ? callAskResult.Pv / underlying.Price.Value : 0.0,
|
|
CallAskVol = callAskResult.Vol,
|
|
|
|
PutAskPrice = putAskResult.Pv,
|
|
PutAskPricePercent = underlying.Price.HasValue ? putAskResult.Pv / underlying.Price.Value : 0.0,
|
|
PutAskVol = putAskResult.Vol,
|
|
});
|
|
}
|
|
|
|
QdpMarketManager.Instance.RemovePrebuiltMarketProxy(qdpMarketId);
|
|
return tQuoteResult;
|
|
}
|
|
|
|
public TQuoteResult Execute(TQuoteRequest quoteRequest, string userGroup = "")
|
|
{
|
|
try
|
|
{
|
|
var valueDate = CalculatorHelper.RealtimeQuoteValueDate();
|
|
|
|
if (quoteRequest.maturityDate < valueDate)
|
|
{
|
|
return new TQuoteResult() { Info = "到期日小于估值日", StatusCode = -1 };
|
|
}
|
|
|
|
var underlying = DataCacheProvider.GetUnderlyingDataSource().GetData(quoteRequest.underlyingCode);
|
|
|
|
if (underlying == null)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
var valueDateStr = valueDate.ToString("yyyy-MM-dd");
|
|
var actualStrikeInteranl = quoteRequest.strikeInterval ?? 100;
|
|
var actualStrikeAccount = quoteRequest.strikeCount ?? 11;
|
|
|
|
Variety variety = null;
|
|
|
|
if (underlying != null)
|
|
{
|
|
variety = DataCacheProvider.GetVarietyDataSource().GetData(underlying.UnderlyingTypeId);
|
|
|
|
if (!quoteRequest.strikeInterval.HasValue)
|
|
{
|
|
using (var db = DbContextFactory.GetYLDbContext())
|
|
{
|
|
var contract = db.underlying_main_contract.FirstOrDefault(x => x.UnderlyingType == underlying.UnderlyingType);
|
|
if (contract != null && contract.StrikeInterval.HasValue)
|
|
{
|
|
actualStrikeInteranl = contract.StrikeInterval.Value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (quoteRequest.spotPrice.HasValue)
|
|
{
|
|
underlying.Price = quoteRequest.spotPrice;
|
|
}
|
|
|
|
if (underlying?.Price == null || underlying.Price < 0.0001)
|
|
{
|
|
return new TQuoteResult() { Info = "价格无效", StatusCode = -1 };
|
|
}
|
|
|
|
underlying.QuotationDate = valueDate;
|
|
|
|
var hasNightMarket = (variety?.HasNightMarket) ?? false;
|
|
var strikes = GetStrikes(underlying.Price ?? 0, actualStrikeInteranl, actualStrikeAccount);
|
|
|
|
//根据用户设置的bid/ask天数调整规则来分别调整到期日
|
|
//TODO: bidMaturityShift和askMaturityShift应该从某数据库表读取
|
|
|
|
var bidMaturityShift = 0;
|
|
var askMaturityShift = 0;
|
|
var otherInfo = "";
|
|
var client_param = ClientPricingParamService.GetPricingParam(valueDate.Date, quoteRequest.maturityDate);
|
|
if (client_param != null)
|
|
{
|
|
askMaturityShift = client_param.ask_tuning_day ?? 0;
|
|
bidMaturityShift = client_param.bid_tuning_day ?? 0;
|
|
otherInfo = client_param.ToJson(); // $"ask到期日偏离{askMaturityShift}天,bid到期日偏离{bidMaturityShift}天";
|
|
}
|
|
var dayCount = CalculatorHelper.GetTradeDayCount();
|
|
//查询
|
|
|
|
var bidMaturityDate = QdpCalendarHelper.ShiftDate(quoteRequest.maturityDate, dayCount, bidMaturityShift).DateTime;
|
|
var askMaturityDate = QdpCalendarHelper.ShiftDate(quoteRequest.maturityDate, dayCount, askMaturityShift).DateTime;
|
|
|
|
var qdpMarketId = Guid.NewGuid().ToString();
|
|
var marketProxy = QdpMarketManager.Instance.GetPrebuiltMarketProxy(qdpMarketId);
|
|
|
|
//使用全局的DiscountCurve以提高计算效率
|
|
var discountCurveName = Guid.NewGuid().ToString();
|
|
var discountCurve = CalculatorHelper.CreateConstantRiskFreeCurve(discountCurveName, valuedateBLL.RiskFreeRate / 100.0);
|
|
marketProxy.AddYieldCurve(discountCurveName, valueDateStr, discountCurve);
|
|
|
|
trade newTrade(int tradeId, double strike, DateTime exerciseDate, string buySell, string optionType)
|
|
{
|
|
return new trade
|
|
{
|
|
id = tradeId,
|
|
TradeType = "香草期权",
|
|
TradeDate = valueDate,
|
|
ExerciseMode = "European",
|
|
Notional = 1,
|
|
BuySell = buySell,
|
|
OptionType = optionType,
|
|
Strike = strike,
|
|
SpotPrice = underlying.Price,
|
|
UnderlyingCode = quoteRequest.underlyingCode,
|
|
UnderlyingInstrumentType = underlying.UnderlyingInstrumentType,
|
|
MaturityDate = exerciseDate,
|
|
ExerciseDate = exerciseDate,
|
|
};
|
|
}
|
|
|
|
if (PS.Config.ErpElement.SkewMapVolConstruction)
|
|
{
|
|
var vol = VolatilityHelper.GetVol(DateTime.Today, "交易", underlying.UnderlyingCode, userGroup);
|
|
var parameter = new VanillaOptionParameter()
|
|
{
|
|
ValueDate = valueDate,
|
|
SpotPrices = new Dictionary<string, double> { { underlying.UnderlyingCode, underlying.Price ?? 0.0 } },
|
|
DiscountCurveName = discountCurveName,
|
|
PreciseTimeMode = true,
|
|
HasNightMarket = hasNightMarket
|
|
};
|
|
|
|
var tQuoteResult = new TQuoteResult() { OtherInfo = otherInfo };
|
|
tQuoteResult.quotaList = new List<TQuoteRecord>();
|
|
|
|
foreach (var strike in strikes)
|
|
{
|
|
var buyCallTrade = newTrade(0, strike, bidMaturityDate, "买入", "看涨");
|
|
|
|
parameter.Volatility = SkewMapVolHelper.GetInterpolatedVol(
|
|
volSurface: vol,
|
|
valueDate: valueDate,
|
|
underlyingCode: underlying.UnderlyingCode,
|
|
exerciseDate: bidMaturityDate,
|
|
strikePrice: strike,
|
|
isBuy: true,
|
|
isCall: true,
|
|
spotPrice: underlying.Price ?? 0);
|
|
|
|
var result = ValueCalculator.CalculateTradeValue(qdpMarketId, buyCallTrade, underlying, parameter);
|
|
var resultRecord = new TQuoteRecord()
|
|
{
|
|
Strike = strike,
|
|
CallBidPrice = Math.Abs(result.Pv),
|
|
CallBidPricePercent = underlying.Price.HasValue ? Math.Abs(result.Pv) / underlying.Price.Value : 0.0,
|
|
CallBidVol = result.Vol,
|
|
};
|
|
|
|
var buyPutTrade = newTrade(0, strike, bidMaturityDate, "买入", "看跌");
|
|
|
|
parameter.Volatility = SkewMapVolHelper.GetInterpolatedVol(
|
|
volSurface: vol,
|
|
valueDate: valueDate,
|
|
underlyingCode: underlying.UnderlyingCode,
|
|
exerciseDate: bidMaturityDate,
|
|
strikePrice: strike,
|
|
isBuy: true,
|
|
isCall: false,
|
|
spotPrice: underlying.Price ?? 0);
|
|
|
|
result = ValueCalculator.CalculateTradeValue(qdpMarketId, buyPutTrade, underlying, parameter);
|
|
resultRecord.PutBidPrice = Math.Abs(result.Pv);
|
|
resultRecord.PutBidPricePercent = underlying.Price.HasValue ? Math.Abs(result.Pv) / underlying.Price.Value : 0.0;
|
|
resultRecord.PutBidVol = result.Vol;
|
|
|
|
var sellCallTrade = newTrade(0, strike, askMaturityDate, "卖出", "看涨");
|
|
|
|
parameter.Volatility = SkewMapVolHelper.GetInterpolatedVol(
|
|
volSurface: vol,
|
|
valueDate: valueDate,
|
|
underlyingCode: underlying.UnderlyingCode,
|
|
exerciseDate: askMaturityDate,
|
|
strikePrice: strike,
|
|
isBuy: false,
|
|
isCall: true,
|
|
spotPrice: underlying.Price ?? 0);
|
|
|
|
result = ValueCalculator.CalculateTradeValue(qdpMarketId, sellCallTrade, underlying, parameter);
|
|
resultRecord.CallAskPrice = Math.Abs(result.Pv);
|
|
resultRecord.CallAskPricePercent = underlying.Price.HasValue ? Math.Abs(result.Pv) / underlying.Price.Value : 0.0;
|
|
resultRecord.CallAskVol = result.Vol;
|
|
|
|
var sellPutTrade = newTrade(0, strike, askMaturityDate, "卖出", "看跌");
|
|
|
|
parameter.Volatility = SkewMapVolHelper.GetInterpolatedVol(
|
|
volSurface: vol,
|
|
valueDate: valueDate,
|
|
underlyingCode: underlying.UnderlyingCode,
|
|
exerciseDate: askMaturityDate,
|
|
strikePrice: strike,
|
|
isBuy: false,
|
|
isCall: false,
|
|
spotPrice: underlying.Price ?? 0);
|
|
|
|
result = ValueCalculator.CalculateTradeValue(qdpMarketId, sellPutTrade, underlying, parameter);
|
|
resultRecord.PutAskPrice = Math.Abs(result.Pv);
|
|
resultRecord.PutAskPricePercent = underlying.Price.HasValue ? Math.Abs(result.Pv) / underlying.Price.Value : 0.0;
|
|
resultRecord.PutAskVol = result.Vol;
|
|
|
|
tQuoteResult.quotaList.Add(resultRecord);
|
|
}
|
|
|
|
tQuoteResult.LatestPrice = underlying.Price.Value;
|
|
if (underlying.PrevClosePrice.HasValue && underlying.PrevClosePrice.Value > 0.0)
|
|
{
|
|
tQuoteResult.Change = OtcFormatHelper.FormatValue(underlying.Price.Value - underlying.PrevClosePrice.Value, 2);
|
|
tQuoteResult.ChangePercent = OtcFormatHelper.FormatValue(tQuoteResult.Change / underlying.PrevClosePrice.Value, 4);
|
|
}
|
|
else
|
|
{
|
|
tQuoteResult.Change = 0.0;
|
|
tQuoteResult.ChangePercent = 0.0;
|
|
}
|
|
|
|
QdpMarketManager.Instance.RemovePrebuiltMarketProxy(qdpMarketId);
|
|
return tQuoteResult;
|
|
}
|
|
else
|
|
{
|
|
var buyCallTrades = new List<trade>();
|
|
var buyPutTrades = new List<trade>();
|
|
var sellCallTrades = new List<trade>();
|
|
var sellPutTrades = new List<trade>();
|
|
var tradeId = 0;
|
|
foreach (var strike in strikes)
|
|
{
|
|
buyCallTrades.Add(newTrade(tradeId, strike, bidMaturityDate, "买入", "看涨"));
|
|
buyPutTrades.Add(newTrade(tradeId, strike, bidMaturityDate, "买入", "看跌"));
|
|
sellCallTrades.Add(newTrade(tradeId, strike, askMaturityDate, "卖出", "看涨"));
|
|
sellPutTrades.Add(newTrade(tradeId, strike, askMaturityDate, "卖出", "看跌"));
|
|
|
|
++tradeId;
|
|
}
|
|
var bidVol = VolatilityHelper.GetVol(DateTime.Today, "报价Bid", underlying.UnderlyingCode, userGroup);
|
|
var askVol = VolatilityHelper.GetVol(DateTime.Today, "报价Ask", underlying.UnderlyingCode, userGroup);
|
|
var parameter = new VanillaOptionParameter()
|
|
{
|
|
ValueDate = valueDate,
|
|
DiscountCurveName = discountCurveName,
|
|
SpotPrices = new Dictionary<string, double>() { { underlying.UnderlyingCode, underlying.Price ?? 0 } },
|
|
PreciseTimeMode = true,
|
|
HasNightMarket = hasNightMarket
|
|
};
|
|
|
|
if (PS.Config.Is润和)
|
|
{
|
|
parameter.OverrideTTM = TradeCalcHelper.CalculateTTMDays(valueDate, bidMaturityDate, 0, false);
|
|
}
|
|
|
|
var callBidResults = ValueCalculator.CalculateOptionsWithSharedVolSurface(
|
|
qdpMarketId,
|
|
buyCallTrades,
|
|
underlying,
|
|
parameter,
|
|
bidVol,
|
|
bidMaturityDate);
|
|
|
|
var putBidResults = ValueCalculator.CalculateOptionsWithSharedVolSurface(
|
|
qdpMarketId,
|
|
buyPutTrades,
|
|
underlying,
|
|
parameter,
|
|
bidVol,
|
|
bidMaturityDate);
|
|
|
|
if (PS.Config.Is润和)
|
|
{
|
|
parameter.OverrideTTM = TradeCalcHelper.CalculateTTMDays(valueDate, askMaturityDate, 0, false);
|
|
}
|
|
|
|
var callAskResults = ValueCalculator.CalculateOptionsWithSharedVolSurface(
|
|
qdpMarketId,
|
|
sellCallTrades,
|
|
underlying,
|
|
parameter,
|
|
askVol,
|
|
askMaturityDate);
|
|
|
|
var putAskResults = ValueCalculator.CalculateOptionsWithSharedVolSurface(
|
|
qdpMarketId,
|
|
sellPutTrades,
|
|
underlying,
|
|
parameter,
|
|
askVol,
|
|
askMaturityDate);
|
|
|
|
var tQuoteResult = new TQuoteResult() { OtherInfo = otherInfo };
|
|
tQuoteResult.quotaList = new List<TQuoteRecord>();
|
|
|
|
for (var i = 0; i < strikes.Length; ++i)
|
|
{
|
|
tQuoteResult.quotaList.Add(new TQuoteRecord()
|
|
{
|
|
Strike = strikes[i],
|
|
CallAskPrice = Math.Abs(callAskResults[i].Pv),
|
|
CallAskPricePercent = underlying.Price.HasValue ? Math.Abs(callAskResults[i].Pv) / underlying.Price.Value : 0.0,
|
|
CallAskVol = callAskResults[i].Vol,
|
|
|
|
CallBidPrice = Math.Abs(callBidResults[i].Pv),
|
|
CallBidPricePercent = underlying.Price.HasValue ? Math.Abs(callBidResults[i].Pv) / underlying.Price.Value : 0.0,
|
|
CallBidVol = callBidResults[i].Vol,
|
|
|
|
PutAskPrice = Math.Abs(putAskResults[i].Pv),
|
|
PutAskPricePercent = underlying.Price.HasValue ? Math.Abs(putAskResults[i].Pv) / underlying.Price.Value : 0.0,
|
|
PutAskVol = putAskResults[i].Vol,
|
|
|
|
PutBidPrice = Math.Abs(putBidResults[i].Pv),
|
|
PutBidPricePercent = underlying.Price.HasValue ? Math.Abs(putBidResults[i].Pv) / underlying.Price.Value : 0.0,
|
|
PutBidVol = putBidResults[i].Vol
|
|
});
|
|
}
|
|
|
|
tQuoteResult.LatestPrice = underlying.Price.Value;
|
|
if (underlying.PrevClosePrice.HasValue && underlying.PrevClosePrice.Value > 0.0)
|
|
{
|
|
tQuoteResult.Change = OtcFormatHelper.FormatValue(underlying.Price.Value - underlying.PrevClosePrice.Value, 2);
|
|
tQuoteResult.ChangePercent = OtcFormatHelper.FormatValue(tQuoteResult.Change / underlying.PrevClosePrice.Value, 4);
|
|
}
|
|
else
|
|
{
|
|
tQuoteResult.Change = 0.0;
|
|
tQuoteResult.ChangePercent = 0.0;
|
|
}
|
|
|
|
QdpMarketManager.Instance.RemovePrebuiltMarketProxy(qdpMarketId);
|
|
return tQuoteResult;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
LogFactory.GetLogger().Error("TQuote", ex);
|
|
return new TQuoteResult() { Info = ex.Message, StatusCode = -1 };
|
|
}
|
|
}
|
|
|
|
private double[] GetStrikes(double spotPrice, int strikeInterval, int strikeCount = 11, bool isAsc = true)
|
|
{
|
|
// 强制将行权价个数调整为奇数
|
|
if (strikeCount % 2 == 0)
|
|
{
|
|
strikeCount += 1;
|
|
}
|
|
|
|
var minInterval = strikeInterval >= 10 ? 10 : strikeInterval;
|
|
|
|
if (strikeCount <= 0)
|
|
{
|
|
throw new Exception($"非法的行权价个数{strikeCount}");
|
|
}
|
|
|
|
var strikes = new double[strikeCount];
|
|
var midIndex = (strikeCount - 1) / 2;
|
|
strikes[midIndex] = spotPrice;
|
|
|
|
var baseStrike = (int)strikes[midIndex];
|
|
var priceDigit = (int)strikes[midIndex] % minInterval;
|
|
|
|
//OTC-4700:
|
|
//当报价间隔大于现价的个位数时,才按10位取整。否则,会出现strike序列错误
|
|
//例如AU1812现价269.60,报价间隔3。如果不做以下判断,baseStrike会是260
|
|
//这样会出现257,269.30,263,266这样错误的序列
|
|
if (strikeInterval > priceDigit)
|
|
{
|
|
baseStrike -= priceDigit;
|
|
}
|
|
|
|
if (isAsc)
|
|
{
|
|
for (var i = midIndex + 1; i < strikeCount; ++i)
|
|
{
|
|
strikes[i] = baseStrike + strikeInterval;
|
|
baseStrike += strikeInterval;
|
|
}
|
|
if (strikeInterval > priceDigit)
|
|
{
|
|
baseStrike = (int)strikes[midIndex] - priceDigit;
|
|
}
|
|
for (var i = midIndex - 1; i >= 0; --i)
|
|
{
|
|
strikes[i] = baseStrike - strikeInterval;
|
|
baseStrike -= strikeInterval;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (var i = midIndex - 1; i >= 0; --i)
|
|
{
|
|
strikes[i] = baseStrike + strikeInterval;
|
|
baseStrike += strikeInterval;
|
|
}
|
|
if (strikeInterval > priceDigit)
|
|
{
|
|
baseStrike = (int)strikes[midIndex] - priceDigit;
|
|
}
|
|
for (var i = midIndex + 1; i < strikeCount; ++i)
|
|
{
|
|
strikes[i] = baseStrike - strikeInterval;
|
|
baseStrike -= strikeInterval;
|
|
}
|
|
}
|
|
|
|
return strikes;
|
|
}
|
|
}
|
|
}
|