
com.tigerbrokers.stock.openapi.client.util.OptionCalcUtils Maven / Gradle / Ivy
package com.tigerbrokers.stock.openapi.client.util;
import com.tigerbrokers.stock.openapi.client.https.client.TigerHttpClient;
import com.tigerbrokers.stock.openapi.client.https.domain.financial.item.CorporateDividendItem;
import com.tigerbrokers.stock.openapi.client.https.domain.option.item.OptionBriefItem;
import com.tigerbrokers.stock.openapi.client.https.domain.option.model.OptionCommonModel;
import com.tigerbrokers.stock.openapi.client.https.domain.quote.item.MarketItem;
import com.tigerbrokers.stock.openapi.client.https.domain.quote.item.RealTimeQuoteItem;
import com.tigerbrokers.stock.openapi.client.https.request.financial.CorporateDividendRequest;
import com.tigerbrokers.stock.openapi.client.https.request.option.OptionBriefQueryRequest;
import com.tigerbrokers.stock.openapi.client.https.request.quote.QuoteMarketRequest;
import com.tigerbrokers.stock.openapi.client.https.request.quote.QuoteRealTimeQuoteRequest;
import com.tigerbrokers.stock.openapi.client.https.response.financial.CorporateDividendResponse;
import com.tigerbrokers.stock.openapi.client.https.response.option.OptionBriefResponse;
import com.tigerbrokers.stock.openapi.client.https.response.quote.QuoteMarketResponse;
import com.tigerbrokers.stock.openapi.client.https.response.quote.QuoteRealTimeQuoteResponse;
import com.tigerbrokers.stock.openapi.client.struct.OptionFundamentals;
import com.tigerbrokers.stock.openapi.client.struct.OptionMetrics;
import com.tigerbrokers.stock.openapi.client.struct.enums.Market;
import com.tigerbrokers.stock.openapi.client.struct.enums.Right;
import com.tigerbrokers.stock.openapi.client.struct.enums.TimeZoneId;
import java.util.concurrent.Callable;
import java.util.concurrent.ThreadFactory;
import org.jquantlib.helper.BSMEuropeanDividendOptionHelper;
import org.jquantlib.helper.FDAmericanDividendOptionHelper;
import org.jquantlib.instruments.Option;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* Options Indicator Calculator
*/
public class OptionCalcUtils {
private static final int TIME_MILLIS_IN_ONE_HOUR = 60 * 60 * 1000;
private static double ACCURACY = 1.0e-6;
private static final String METRIC_PARAM_FORMAT = "rates=%s;expiry=%s;latestPrice=%s;target=%s;ask=%s;bid=%s;dividendAmount=%s";
private static double n(double x) {
return (1 / Math.sqrt(2 * Math.PI)) * Math.exp(-x * x / 2);
}
private static ExecutorService executorService = new ThreadPoolExecutor(4, 4,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(1024), new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = Executors.defaultThreadFactory().newThread(r);
t.setDaemon(true);
return t;
}
}
, new ThreadPoolExecutor.AbortPolicy());
private static double N(double z) {
if (z > 6.0) {
return 1.0;
}
if (z < -6.0) {
return 0.0;
}
double b1 = 0.31938153;
double b2 = -0.356563782;
double b3 = 1.781477937;
double b4 = -1.821255978;
double b5 = 1.330274429;
double p = 0.2316419;
double c2 = 0.3989423;
double a = Math.abs(z);
double t = 1.0 / (1.0 + a * p);
double b = c2 * Math.exp((-z) * (z / 2.0));
double n = ((((b5 * t + b4) * t + b3) * t + b2) * t + b1) * t;
n = 1.0 - b * n;
if (z < 0.0) {
n = 1.0 - n;
}
return n;
}
private static double call(double S, double X, double r, double q, double sigma, double time) {
double sigma_sqr = Math.pow(sigma, 2);
double time_sqrt = Math.sqrt(time);
double d1 = (Math.log(S / X) + (r - q + 0.5 * sigma_sqr) * time) / (sigma * time_sqrt);
double d2 = d1 - (sigma * time_sqrt);
return S * Math.exp(-q * time) * N(d1) - X * Math.exp(-r * time) * N(d2);
}
private static double put(double S, double K, double r, double q, double sigma, double time) {
double sigma_sqr = Math.pow(sigma, 2);
double time_sqrt = Math.sqrt(time);
double d1 = (Math.log(S / K) + (r - q + 0.5 * sigma_sqr) * time) / (sigma * time_sqrt);
double d2 = d1 - (sigma * time_sqrt);
return K * Math.exp(-r * time) * N(-d2) - S * Math.exp(-q * time) * N(-d1);
}
private static double optionPriceAmericanCallApproximatedBaw(double S, double X, double r, double b, double sigma,
double time) {
double sigma_sqr = sigma * sigma;
double time_sqrt = Math.sqrt(time);
double nn = 2.0 * b / sigma_sqr;
double m = 2.0 * r / sigma_sqr;
double K = 1.0 - Math.exp(-r * time);
double q2 = (-(nn - 1) + Math.sqrt(Math.pow((nn - 1), 2.0) + (4 * m / K))) * 0.5;
// seed value from paper
double q2_inf = 0.5 * (-(nn - 1.0) + Math.sqrt(Math.pow((nn - 1), 2.0) + 4.0 * m));
double S_star_inf = X / (1.0 - 1.0 / q2_inf);
double h2 = -(b * time + 2.0 * sigma * time_sqrt) * (X / (S_star_inf - X));
double S_seed = X + (S_star_inf - X) * (1.0 - Math.exp(h2));
int no_iterations = 0; // iterate on S to find S_star, using Newton steps
double Si = S_seed;
double g = 1;
double gprime = 1.0;
while ((Math.abs(g) > ACCURACY) && (Math.abs(gprime) > ACCURACY) // to avoid exploding Newton's
&& (no_iterations++ < 500) && (Si > 0.0) && !Double.isNaN(Si)) {
double c = call(Si, X, r, b, sigma, time);
double d1 = (Math.log(Si / X) + (b + 0.5 * sigma_sqr) * time) / (sigma * time_sqrt);
g = (1.0 - 1.0 / q2) * Si - X - c + (1.0 / q2) * Si * Math.exp((b - r) * time) * N(d1);
gprime = (1.0 - 1.0 / q2) * (1.0 - Math.exp((b - r) * time) * N(d1)) +
(1.0 / q2) * Math.exp((b - r) * time) * n(d1) * (1.0 / (sigma * time_sqrt));
Si = Si - (g / gprime);
}
double S_star = 0;
if (Math.abs(g) > ACCURACY) {
S_star = S_seed;
} // did not converge
else {
S_star = Si;
}
double C = 0;
double c = call(S, X, r, b, sigma, time);
if (S >= S_star) {
C = S - X;
} else {
double d1 = (Math.log(S_star / X) + (b + 0.5 * sigma_sqr) * time) / (sigma * time_sqrt);
double A2 = (1.0 - Math.exp((b - r) * time) * N(d1)) * (S_star / q2);
C = c + A2 * Math.pow((S / S_star), q2);
}
return Double.isNaN(C) ? c : Math.max(C, c); // know value will never be less than BS value
}
private static double optionPriceAmericanPutApproximatedBaw(double S, double X, double r, double b, double sigma,
double time) {
double sigma_sqr = sigma * sigma;
double time_sqrt = Math.sqrt(time);
double M = 2.0 * r / sigma_sqr;
double NN = 2.0 * b / sigma_sqr;
double K = 1.0 - Math.exp(-r * time);
double q1 = 0.5 * (-(NN - 1) - Math.sqrt(Math.pow((NN - 1), 2.0) + (4.0 * M / K)));
// now find initial S value
double q1_inf = 0.5 * (-(NN - 1) - Math.sqrt(Math.pow((NN - 1), 2.0) + 4.0 * M));
double S_star_star_inf = X / (1.0 - 1.0 / q1_inf);
double h1 = (b * time - 2 * sigma * time_sqrt) * (X / (X - S_star_star_inf));
double S_seed = S_star_star_inf + (X - S_star_star_inf) * Math.exp(h1);
double Si = S_seed; // now do Newton iterations to solve for S**
int no_iterations = 0;
double g = 1;
double gprime = 1;
while ((Math.abs(g) > ACCURACY) && (Math.abs(gprime) > ACCURACY) // to avoid non-convergence
&& (no_iterations++ < 500) && Si > 0.0 && !Double.isNaN(Si)) {
double p = put(Si, X, r, b, sigma, time);
double d1 = (Math.log(Si / X) + (b + 0.5 * sigma_sqr) * time) / (sigma * time_sqrt);
g = X - Si - p + (1 - Math.exp((b - r) * time) * N(-d1)) * Si / q1;
gprime = (1.0 / q1 - 1.0) * (1.0 - Math.exp((b - r) * time) * N(-d1)) +
(1.0 / q1) * Math.exp((b - r) * time) * (1.0 / (sigma * time_sqrt)) * n(-d1);
Si = Si - (g / gprime);
}
double S_star_star = Si;
if (g > ACCURACY) {
S_star_star = S_seed;
}
double P = 0;
double p = put(S, X, r, b, sigma, time);
if (S > S_star_star) {
double d1 = (Math.log(S_star_star / X) + (b + 0.5 * sigma_sqr) * time) / (sigma * time_sqrt);
double A1 = -(S_star_star / q1) * (1 - Math.exp((b - r) * time) * N(-d1));
P = p + A1 * Math.pow((S / S_star_star), q1);
} else {
P = X - S;
}
return Math.max(P, p); // should not be lower than Black Scholes value
}
/**
* Buy Profit Probability
*/
private static double optionBuyCallProfitRate(double S, double K, double p, double r, double sigma, double time) {
double time_sqrt = Math.sqrt(time);
double d1 = Math.log(S / (K + p)) + r * time;
double d2 = sigma * time_sqrt;
return N(d1 / d2);
}
/**
* Buy Profit Probability
*/
private static double optionBuyPutProfitRate(double S, double K, double p, double r, double sigma, double time) {
double time_sqrt = Math.sqrt(time);
double d1 = Math.log(S / (K - p)) + r * time;
double d2 = sigma * time_sqrt;
double result = N(d1 / d2);
return 1 - result;
}
/**
* Calculate the implied volatility of a call
*
* @param target target price
* @param S 股票 价格
* @param X 行权价格
* @param r 国债利率
* @param b =r
* @param time 时间,以年为单位半年是0.5
*/
private static double getVolatilityCall(double target, double S, double X, double r, double b, double time) {
double min = 0;
double max = 2.5;
double sig = min;
double x = 1000;
int maxCount = 100;
while (Math.abs(x - target) > 0.001 && maxCount-- > 0) {
sig = (min + max) / 2;
x = optionPriceAmericanCallApproximatedBaw(S, X, r, b, sig, time);
if (x < target) {
min = sig;
} else if (x > target) {
max = sig;
}
}
return sig;
}
private static double getTimeValueCall(double strike, double spot, double price) {
double res = 0;
if (strike > spot) {
res = price;
} else {
res = price + strike - spot;
}
return res;
}
private static double getTimeValuePut(double strike, double spot, double price) {
double res = 0;
if (strike < spot) {
res = price;
} else {
res = price - (strike - spot);
}
return res;
}
/**
* Calculate the implied volatility of a put
*
* @param target 目标价
* @param S 股票 价格
* @param X 行权价格
* @param r 国债利率
* @param b =r
* @param time 时间,以年为单位半年是0.5
*/
private static double getVolatilityPut(double target, double S, double X, double r, double b, double time) {
double min = 0;
double max = 2.5;
double sig = min;
double x = 1000;
int maxCount = 100;
while (Math.abs(x - target) > 0.001 && maxCount-- > 0) {
sig = (min + max) / 2;
x = optionPriceAmericanPutApproximatedBaw(S, X, r, b, sig, time);
if (x < target) {
min = sig;
} else if (x > target) {
max = sig;
}
}
return sig;
}
private static OptionMetrics optionPricePartialsCallBlackScholes(double S, // spot price
double K, // Strike (exercise) price,
double r, // interest rate
double sigma, // volatility
double time) { // partial wrt r
double time_sqrt = Math.sqrt(time);
double d1 = (Math.log(S / K) + r * time) / (sigma * time_sqrt) + 0.5 * sigma * time_sqrt;
double d2 = d1 - (sigma * time_sqrt);
double Delta = N(d1);
double Gamma = n(d1) / (S * sigma * time_sqrt);
double Theta = (-(S * sigma * n(d1)) / (2 * time_sqrt) - r * K * Math.exp(-r * time) * N(d2)) / 365f;
double Vega = S * time_sqrt * n(d1) / 100f;
double Rho = K * time * Math.exp(-r * time) * N(d2);
return new OptionMetrics(Delta, Gamma, Theta, Vega, Rho);
}
private static OptionMetrics optionPricePartialsPutBlackScholes(double S, // spot price
double K, // Strike (exercise) price,
double r, // interest rate
double sigma, double time) { // partial wrt r
double time_sqrt = Math.sqrt(time);
double d1 = (Math.log(S / K) + r * time) / (sigma * time_sqrt) + 0.5 * sigma * time_sqrt;
double d2 = d1 - (sigma * time_sqrt);
double Delta = -N(-d1);
double Gamma = n(d1) / (S * sigma * time_sqrt);
double Theta = (-(S * sigma * n(d1)) / (2 * time_sqrt) + r * K * Math.exp(-r * time) * N(-d2)) / 365f;
double Vega = S * time_sqrt * n(d1) / 100f;
double Rho = -K * time * Math.exp(-r * time) * N(-d2);
return new OptionMetrics(Delta, Gamma, Theta, Vega, Rho);
}
/**
* 溢价率
*/
private static double calcPutPremiumRate(double opPrice, double stockPrice, double strike) {
return (strike - opPrice - stockPrice) / stockPrice;
}
/**
* 溢价率
*/
private static double calcCallPremiumRate(double opPrice, double stockPrice, double strike) {
return (strike + opPrice - stockPrice) / stockPrice;
}
/**
* 杠杆率
*/
private static double getLeverage(double targetPrice, double latestPrice, double delta) {
return Math.abs(delta * latestPrice) / targetPrice;
}
/**
* 内在价值
*/
private static double getInsideValue(String right, double latestPrice, double strike) {
double value = "CALL".equalsIgnoreCase(right) ? latestPrice - strike : strike - latestPrice;
if (value < 0) {
value = 0;
}
return value;
}
/**
* 计算期权基本面信息
*
* @param r 国债利率
* @param expiryLong 过期日(long类型)
* @param executeDateLong 除权除息日(long类型),与expiryLong保持时区一致
* @param latestPrice 最新正股价格
* @param targetPrice 期权目标价格
* @param dividendAmount 分红
* @param strike 行权价
* @param type CALL or PUT
* @param currentTime 当前时间(long类型),与expiryLong保持时区一致
* @param isTrading 是否在正股交易时间
*/
private static OptionFundamentals calcOptionIndex(double r, long expiryLong, long executeDateLong,
double latestPrice, double targetPrice, double dividendAmount, double strike, String type, long currentTime,
boolean isTrading) {
OptionFundamentals result = new OptionFundamentals();
double diff = ((expiryLong - currentTime) /
(24.0f * TIME_MILLIS_IN_ONE_HOUR) + 1 + (isTrading ? 0 : 1)) / 365.0f;
final boolean needDividend =
executeDateLong != 0 && expiryLong > executeDateLong && currentTime < executeDateLong;
latestPrice = latestPrice - (needDividend ? dividendAmount : 0);
if (targetPrice == 0 || strike == 0) {
return null;
}
double sigma = 0;
OptionMetrics optionMetrics;
if (Right.PUT.name().equalsIgnoreCase(type) && targetPrice > strike - latestPrice) {
result.setTimeValue(getTimeValuePut(strike, latestPrice, targetPrice));
sigma = getVolatilityPut(targetPrice, latestPrice, strike, r, r, diff);
optionMetrics = optionPricePartialsPutBlackScholes(latestPrice, strike, r, sigma, diff);
result.setPremiumRate(calcPutPremiumRate(targetPrice, latestPrice, strike) * 100);
result.setProfitRate(optionBuyPutProfitRate(latestPrice, strike, targetPrice, r, sigma, diff) * 100);
} else if (Right.CALL.name().equalsIgnoreCase(type) && targetPrice > latestPrice - strike) {
result.setTimeValue(getTimeValueCall(strike, latestPrice, targetPrice));
sigma = getVolatilityCall(targetPrice, latestPrice, strike, r, r, diff);
result.setPremiumRate(calcCallPremiumRate(targetPrice, latestPrice, strike) * 100);
result.setProfitRate(optionBuyCallProfitRate(latestPrice, strike, targetPrice, r, sigma, diff) * 100);
optionMetrics = optionPricePartialsCallBlackScholes(latestPrice, strike, r, sigma, diff);
} else {
optionMetrics = new OptionMetrics(Double.NaN, Double.NaN, Double.NaN, Double.NaN, Double.NaN);
}
result.setDelta(optionMetrics.getDelta());
result.setGamma(optionMetrics.getGamma());
result.setTheta(optionMetrics.getTheta());
result.setVega(optionMetrics.getVega());
result.setRho(optionMetrics.getRho());
result.setVolatility(sigma * 100);
result.setLeverage(getLeverage(targetPrice, latestPrice, result.getDelta()));
result.setInsideValue(getInsideValue(type, latestPrice, strike));
return result;
}
private static boolean isEmpty(List list) {
return list == null || list.isEmpty();
}
/**
* Get option fundamental information(include option greek values)
*
* @param client TigerHttpClient
* @param symbol Stock code
* @param right CALL or PUT
* @param strike strike price
* @param expiry Expiration date(yyyy-MM-dd)
* @return option fundamental information
* @throws Exception runtime exception
*/
public static OptionFundamentals getOptionFundamentals(TigerHttpClient client, String symbol, String right,
String strike, String expiry) throws Exception {
return getOptionFundamentals(client, symbol, right, strike, expiry, null);
}
/**
* Get option fundamental information(include option greek values)
*
* @param client TigerHttpClient
* @param symbol Stock code
* @param right CALL or PUT
* @param strike strike price
* @param expiry Expiration date(yyyy-MM-dd)
* @param underlyingSymbol underlying symbol(if null, If empty, defaults to the same value as 'symbol')
* @return option fundamental information
* @throws Exception runtime exception
*/
public static OptionFundamentals getOptionFundamentals(TigerHttpClient client, String symbol, String right,
String strike, String expiry, String underlyingSymbol) throws Exception {
if (DateUtils.isDateBeforeToday(expiry, TimeZoneId.NewYork)) {
throw new RuntimeException("Option expiration date cannot be earlier than the current date.");
}
if (StringUtils.isEmpty(underlyingSymbol)) {
underlyingSymbol = symbol;
}
FutureTask dividendTask = getCorporateDividendTask(client, underlyingSymbol);
FutureTask marketStateTask = getMarketStateTask(client);
FutureTask latestPriceTask = getLatestPriceTask(client, underlyingSymbol);
FutureTask optionBriefTask =
getOptionBriefTask(client, symbol, right, strike, DateUtils.parseEpochMill(expiry, TimeZoneId.NewYork));
OptionBriefItem optionBriefItem = optionBriefTask.get();
if (optionBriefItem.getAskPrice() == null) {
optionBriefItem.setAskPrice(0D);
}
if (optionBriefItem.getBidPrice() == null) {
optionBriefItem.setBidPrice(0D);
}
double target = (optionBriefItem.getAskPrice() + optionBriefItem.getBidPrice()) / 2;
if (optionBriefItem.getStrike() == null || target <= 0D) {
throw new RuntimeException("Unable to obtain option summary information.");
}
Double latestPrice = latestPriceTask.get();
Double dividendAmount = dividendTask.get().getAmount();
OptionFundamentals result =
calcOptionIndex(optionBriefItem.getRatesBonds(), optionBriefItem.getExpiry(),
DateUtils.parseEpochMill(dividendTask.get().getExecuteDate()), latestPrice, target,
dividendAmount, Double.parseDouble(optionBriefItem.getStrike()), optionBriefItem.getRight(),
System.currentTimeMillis(), marketStateTask.get());
result.setOpenInterest(optionBriefItem.getOpenInterest() == null ? 0 : optionBriefItem.getOpenInterest());
String volatility = null;
if (optionBriefItem.getVolatility() != null && optionBriefItem.getVolatility().contains("%")) {
volatility = optionBriefItem.getVolatility().replaceAll("%", "");
}
double historyVolatility = volatility == null || volatility.isEmpty() ? 0.0 : Double.parseDouble(volatility);
result.setHistoryVolatility(historyVolatility);
result.setMetricParam(String.format(METRIC_PARAM_FORMAT,optionBriefItem.getRatesBonds(), optionBriefItem.getExpiry(),latestPrice ,target,optionBriefItem.getAskPrice(),optionBriefItem.getBidPrice(),dividendAmount));
return result;
}
private static FutureTask getCorporateDividendTask(TigerHttpClient client, String symbol) {
FutureTask corporateDividendTask = new FutureTask<>(new Callable() {
@Override
public CorporateDividendItem call() throws Exception {
List symbols = new ArrayList<>();
symbols.add(symbol);
Date date = Date.from(LocalDate.now().atStartOfDay(ZoneId.of(TimeZoneId.Shanghai.getZoneId())).toInstant());
CorporateDividendRequest request = CorporateDividendRequest.newRequest(symbols, Market.US, date, date);
CorporateDividendResponse corporateDividendResponse = client.execute(request);
if (corporateDividendResponse != null && corporateDividendResponse.isSuccess()) {
List corporateDividendItems = corporateDividendResponse.getItems().get(symbol);
if (!isEmpty(corporateDividendItems)) {
return corporateDividendItems.get(0);
}
}
CorporateDividendItem item = new CorporateDividendItem();
item.setAmount(0D);
return item;
}
});
executorService.execute(corporateDividendTask);
return corporateDividendTask;
}
private static FutureTask getMarketStateTask(TigerHttpClient client) {
FutureTask marketItemTask = new FutureTask<>(new Callable() {
@Override
public Boolean call() throws Exception {
QuoteMarketResponse quoteMarketResponse = client.execute(QuoteMarketRequest.newRequest(Market.US));
if (quoteMarketResponse != null && quoteMarketResponse.isSuccess()) {
List marketItems = quoteMarketResponse.getMarketItems();
if (!isEmpty(marketItems)) {
return "TRADING".equals(marketItems.get(0).getStatus());
}
}
return false;
}
});
executorService.execute(marketItemTask);
return marketItemTask;
}
private static FutureTask getLatestPriceTask(TigerHttpClient client, String symbol) {
FutureTask realTimeQuoteItemTask = new FutureTask<>(new Callable() {
@Override
public Double call() throws Exception {
QuoteRealTimeQuoteResponse quoteRealTimeQuoteResponse =
client.execute(QuoteRealTimeQuoteRequest.newRequest(Arrays.asList(symbol)));
if (quoteRealTimeQuoteResponse != null && quoteRealTimeQuoteResponse.isSuccess()) {
List realTimeQuoteItems = quoteRealTimeQuoteResponse.getRealTimeQuoteItems();
if (!isEmpty(realTimeQuoteItems)) {
Double latestPrice = realTimeQuoteItems.get(0).getLatestPrice();
if (latestPrice == null) {
throw new RuntimeException("Failed to get the latest price of the stock.");
}
return latestPrice;
}
}
if (quoteRealTimeQuoteResponse == null) {
throw new RuntimeException("Failed to get the latest price of the stock.");
}
throw new RuntimeException("Get realtime-quotes return error description: " + quoteRealTimeQuoteResponse.getMessage());
}
});
executorService.execute(realTimeQuoteItemTask);
return realTimeQuoteItemTask;
}
private static FutureTask getOptionBriefTask(TigerHttpClient client, String symbol, String right,
String strike, long expiryDate) {
FutureTask optionBriefItemTask = new FutureTask<>(new Callable() {
@Override
public OptionBriefItem call() throws Exception {
OptionCommonModel model = new OptionCommonModel(symbol, right, strike, expiryDate);
OptionBriefResponse optionBriefResponse = client.execute(OptionBriefQueryRequest.of(model));
List briefItems;
if (optionBriefResponse != null && optionBriefResponse.isSuccess()) {
briefItems = optionBriefResponse.getOptionBriefItems();
if (!isEmpty(briefItems)) {
return briefItems.get(0);
}
}
if (optionBriefResponse == null) {
throw new RuntimeException("Unable to obtain option summary info.");
}
throw new RuntimeException("Obtain option brief summary info return error description:" + optionBriefResponse.getMessage());
}
});
executorService.execute(optionBriefItemTask);
return optionBriefItemTask;
}
public static OptionFundamentals calcOptionIndex(Right optionType, double underlying, double strike, double riskFreeRate,
double dividendRate, double impliedVolatility, LocalDate settlementDate, LocalDate expirationDate) {
FDAmericanDividendOptionHelper helper = new FDAmericanDividendOptionHelper(optionType == Right.CALL ? Option.Type.Call : Option.Type.Put, underlying, strike,
riskFreeRate, dividendRate, impliedVolatility,
new org.jquantlib.time.Date(settlementDate.getDayOfMonth(), settlementDate.getMonthValue(), settlementDate.getYear()),
new org.jquantlib.time.Date(expirationDate.getDayOfMonth(), expirationDate.getMonthValue(), expirationDate.getYear()),
new ArrayList<>(), new ArrayList<>());
OptionMetrics optionIndex = new OptionMetrics(helper.delta(), helper.gamma(), helper.theta(), helper.vega(), helper.rho());
OptionFundamentals optionFundamentals = new OptionFundamentals();
optionFundamentals.setDelta(optionIndex.getDelta());
optionFundamentals.setGamma(optionIndex.getGamma());
optionFundamentals.setTheta(optionIndex.getTheta());
optionFundamentals.setVega(optionIndex.getVega());
optionFundamentals.setRho(optionIndex.getRho());
optionFundamentals.setPredictedValue(helper.NPV());
return optionFundamentals;
}
public static OptionFundamentals calcOptionIndex(Right optionType, double underlying, double strike, double riskFreeRate,
double dividendRate, Double askPrice, Double bidPrice, LocalDate settlementDate, LocalDate expirationDate) {
FDAmericanDividendOptionHelper helper = new FDAmericanDividendOptionHelper(optionType == Right.CALL ? Option.Type.Call : Option.Type.Put, underlying, strike,
riskFreeRate, dividendRate,
new org.jquantlib.time.Date(settlementDate.getDayOfMonth(), settlementDate.getMonthValue(), settlementDate.getYear()),
new org.jquantlib.time.Date(expirationDate.getDayOfMonth(), expirationDate.getMonthValue(), expirationDate.getYear()));
double ivol = helper.impliedVolatility(calculateAvgPrice(askPrice,bidPrice));
helper.updateImpliedVolatility(ivol);
OptionMetrics optionIndex = new OptionMetrics(helper.delta(), helper.gamma(), helper.theta(), helper.vega(), helper.rho());
OptionFundamentals optionFundamentals = new OptionFundamentals();
optionFundamentals.setDelta(optionIndex.getDelta());
optionFundamentals.setGamma(optionIndex.getGamma());
optionFundamentals.setTheta(optionIndex.getTheta());
optionFundamentals.setVega(optionIndex.getVega());
optionFundamentals.setRho(optionIndex.getRho());
optionFundamentals.setPredictedValue(helper.NPV());
return optionFundamentals;
}
public static OptionFundamentals calcEuropeanOptionIndex(Right optionType, double underlying, double strike, double riskFreeRate,
double dividendRate, Double askPrice, Double bidPrice, LocalDate settlementDate, LocalDate expirationDate) {
BSMEuropeanDividendOptionHelper helper = new BSMEuropeanDividendOptionHelper(optionType == Right.CALL ? Option.Type.Call : Option.Type.Put, underlying, strike,
riskFreeRate, dividendRate,
new org.jquantlib.time.Date(settlementDate.getDayOfMonth(), settlementDate.getMonthValue(), settlementDate.getYear()),
new org.jquantlib.time.Date(expirationDate.getDayOfMonth(), expirationDate.getMonthValue(), expirationDate.getYear()));
double ivol = helper.impliedVolatility(calculateAvgPrice(askPrice,bidPrice));
helper.updateImpliedVolatility(ivol);
OptionMetrics optionIndex = new OptionMetrics(helper.delta(), helper.gamma(), helper.theta(), helper.vega(), helper.rho());
OptionFundamentals optionFundamentals = new OptionFundamentals();
optionFundamentals.setDelta(optionIndex.getDelta());
optionFundamentals.setGamma(optionIndex.getGamma());
optionFundamentals.setTheta(optionIndex.getTheta());
optionFundamentals.setVega(optionIndex.getVega());
optionFundamentals.setRho(optionIndex.getRho());
optionFundamentals.setPredictedValue(helper.NPV());
return optionFundamentals;
}
public static double calculateAvgPrice(Double askPrice, Double bidPrice) {
double avgPrice;
if (askPrice == null && bidPrice == null) {
avgPrice = 0D;
} else if (askPrice != null && bidPrice != null) {
avgPrice = (askPrice + bidPrice) / 2;
} else {
avgPrice = askPrice == null ? bidPrice : askPrice;
}
return avgPrice;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy