Search Framework:
OptionSynthetic
Namespace: WealthLab.Data
Parent: Object

OptionSynthetic is a static utility class that generates synthetic option symbols and calculated option price histories. It also provides methods for calculating option prices and Greeks using the Black-Scholes model. Synthetic option calculations require an estimate of implied volatility (IV). The resulting prices and Greeks will only approximate actual option values to the extent that the supplied IV accurately represents the option's implied volatility. OptionSynthetic is particularly useful when developing and backtesting option trading strategies when historical option contracts or option chains are not available.

Methods
CalculateOptionPrice
public static double CalculateOptionPrice(string optionSymbol, double impliedVolatility, double priceUnderlying, DateTime dateTime)

Calculates a hypothetical option price using the Black-Scholes model. Pass the option contract symbol in optionSymbol, the estimated implied volatility in impliedVolatility, the hypothetical underlying price in priceUnderlying, and the date/time for which the calculation should be performed in dateTime. If dateTime is on or after the option's expiration, the method returns the option's intrinsic value instead of a Black-Scholes calculated value.

Example Code
using WealthLab.Backtest;
using WealthLab.Core;
using WealthLab.Data;
namespace WealthScript
{
    public class MyStrategy : UserStrategyBase
    {
        public override void Initialize(BarHistory bars)
        {
            double iv = 0.25;
            DateTime exDate = bars.NextOptionExpiryDate(bars.Count - 1);
            //ATM call for next monthly expiration
            string atmCall = OptionSynthetic.GetOptionsSymbol(
                bars, OptionType.Call, bars.LastValue, bars.EndDate, 1);
            //calculate its value with the stock 10% higher,
            //one week before expiration
            double stkPrice = bars.LastValue * 1.1;
            double optionPrice = OptionSynthetic.CalculateOptionPrice(
                atmCall, iv, stkPrice, exDate.AddDays(-7));
            DrawHeaderText(
                $"{atmCall} value on {exDate.AddDays(-7):yyyy-MM-dd}",
                WLColor.NeonGreen, 14);
            DrawHeaderText(
                $"for {bars.Symbol} at {stkPrice:N2} is {optionPrice:N2}",
                WLColor.NeonGreen, 14);
        }
        public override void Execute(BarHistory bars, int idx)
        {
        }
    }
}

GetGreeks
public static OptionGreek GetGreeks(BarHistory underlier, int bar, OptionType optionType, double strike, DateTime expiration, double iv = 0.2)
public static OptionGreek GetGreeks(BarHistory underlier, int bar, string optionSymbol, double iv = 0.2)

Calculates option Greeks for the specified bar of the underlying BarHistory and returns the results in an OptionGreek instance. The calculated values include OptionPrice, Delta, Theta, Gamma, and Vega. The method uses the Black-Scholes model and the supplied iv as the option's implied volatility estimate.

Example Code
using WealthLab.Backtest;
using WealthLab.Core;
using WealthLab.Data;
using WealthLab.Indicators;
namespace WealthScript
{
    public class OptionSyntheticGreeks : UserStrategyBase
    {
        public override void Initialize(BarHistory bars)
        {
            //estimate a varying IV using a factor of HV
            TimeSeries iv = HV.Series(bars.Close, 89, 144) / 100d;
            string symbol = OptionSynthetic.GetOptionsSymbol(
                bars,
                OptionType.Call,
                bars.Close.LastValue,
                bars.DateTimes[bars.Count - 1],
                3);
            _osyn = OptionSynthetic.GetHistory(bars, symbol, iv);
            PlotBarHistory(_osyn, "OSYN", WLColor.Cyan);
            //Greeks at the last bar
            OptionGreek og = OptionSynthetic.GetGreeks(
                bars, bars.Count - 1, symbol, iv.LastValue);
            DrawHeaderText(og.Symbol + ": " + og.OptionPrice.ToString("$0.00"),
                WLColor.Cyan, 12, "OSYN");
            DrawHeaderText("Delta: " + og.Delta.ToString("N2"),
                WLColor.Cyan, 12, "OSYN");
            DrawHeaderText("Theta: " + og.Theta.ToString("N2"),
                WLColor.Cyan, 12, "OSYN");
            DrawHeaderText("Gamma: " + og.Gamma.ToString("N2"),
                WLColor.Cyan, 12, "OSYN");
            DrawHeaderText("Vega: " + og.Vega.ToString("N2"),
                WLColor.Cyan, 12, "OSYN");
        }
        public override void Execute(BarHistory bars, int idx)
        {
        }
        private BarHistory _osyn;
    }
}

GetHistory
public static BarHistory GetHistory(BarHistory underlier, OptionType optionType, double strike, DateTime expiration, double iv = 0.2)
public static BarHistory GetHistory(BarHistory underlier, OptionType optionType, double strike, DateTime expiration, TimeSeries iv)
public static BarHistory GetHistory(BarHistory underlier, string optionSymbol, double iv = 0.2)
public static BarHistory GetHistory(BarHistory underlier, string optionSymbol, TimeSeries iv)

Returns a calculated BarHistory representing a synthetic option contract. The synthetic option's OHLC values are calculated from the corresponding OHLC values of the underlier using the Black-Scholes model. You can supply either a constant implied volatility or a TimeSeries containing a varying implied volatility estimate. When using an optionSymbol overload, OptionSynthetic parses the option type, strike, and expiration from the supplied symbol. The resulting synthetic BarHistory is cached in the underlying BarHistory's Cache using the synthetic option symbol as the key.

Example Code
using WealthLab.Backtest;
using WealthLab.Core;
using WealthLab.Data;
namespace WealthScript
{
    public class SyntheticOptionBars : UserStrategyBase
    {
        public override void Initialize(BarHistory bars)
        {
            //get the Put with the closest strike to the last chart value
            string symbol = OptionSynthetic.GetOptionsSymbol(
                bars,
                OptionType.Put,
                bars.Close.LastValue,
                bars.DateTimes[bars.Count - 1],
                3);
            //create and plot the synthetic option history
            _osyn = OptionSynthetic.GetHistory(bars, symbol, 0.2);
            PlotBarHistory(_osyn, "OSYN", WLColor.LightCyan);
        }
        public override void Execute(BarHistory bars, int idx)
        {
        }
        private BarHistory _osyn;
    }
}

GetOptionsSymbol
public static string GetOptionsSymbol(
BarHistory underlier,
OptionType optionType,
double price,
DateTime currentDate,
int minDaysAhead = 0,
bool useWeeklies = false,
bool allowExpired = false,
bool closestStrike = true,
bool priceIsStrike = false)

Generates a synthetic option contract symbol based on the supplied underlying BarHistory, option type, price, and expiration criteria. Pass OptionType.Call or OptionType.Put in optionType. The price parameter represents the price near the desired strike. Unless priceIsStrike is true, OptionSynthetic converts this value to an appropriate synthetic strike using the following increments: | Underlying Price | Strike Increment | | --- | --- | | Above $1,000 | $25 | | Above $200 | $10 | | Above $10 | $5 | | $10 or below | $1 | If closestStrike is true, the strike closest to price is selected. If false, the next higher strike is selected for calls and the next lower strike for puts. Set priceIsStrike to true to use price directly as the strike without adjustment. The expiration is determined from currentDate, minDaysAhead, and useWeeklies. Set allowExpired to true when backtesting synthetic options so historical expiration dates can be generated.

Example Code
using WealthLab.Backtest;
using WealthLab.Core;
using WealthLab.Data;
namespace WealthScript
{
    public class SyntheticOptionSymbol : UserStrategyBase
    {
        public override void Initialize(BarHistory bars)
        {
            double price = bars.Close[bars.Count - 1];
            DateTime currentDate = bars.DateTimes[bars.Count - 1];
            string optSym = OptionSynthetic.GetOptionsSymbol(
                bars,
                OptionType.Call,
                price,
                currentDate,
                minDaysAhead: 0,
                useWeeklies: false,
                allowExpired: true,
                closestStrike: true);
            DrawHeaderText("ATM Call: " + optSym, WLColor.NeonGreen, 14);
        }
        public override void Execute(BarHistory bars, int idx)
        {
        }
    }
}

GetSymbolExpiry
[Obsolete("Use OptionsHelper.SymbolExpiry() for all option formats.")]
public static DateTime GetSymbolExpiry(string optionSymbol)

Parses optionSymbol and returns its expiration date. This method is obsolete. Use OptionsHelper.SymbolExpiry instead.


GetSymbolStrike
[Obsolete("Use OptionsHelper.SymbolStrike() for all option formats.")]
public static double GetSymbolStrike(string optionSymbol)

Parses optionSymbol and returns its strike price. This method is obsolete. Use OptionsHelper.SymbolStrike instead.


ImpliedVolatility
public static double ImpliedVolatility(BarHistory source, string optionSymbol, double atPrice, DateTime asOfDate)

Attempts to calculate implied volatility using an iterative Newton-Raphson calculation. The current implementation is marked in the source code as not yet accurate and needing further work. It should therefore not be relied upon for precise implied volatility calculations.


Symbol
public static string Symbol(BarHistory underlier, OptionType optionType, double strike, DateTime expiration)

Returns a synthetic option symbol for the specified underlying BarHistory, option type, strike, and expiration. Synthetic option symbols begin with ! and use the following format:

![underlier]yyMMdd[C/P][strike]

For example:

!SPY260918C650

The Symbol method lets you specify the strike and expiration exactly, whereas GetOptionsSymbol determines them according to its strike and expiration selection rules.

Example Code
using WealthLab.Backtest;
using WealthLab.Core;
using WealthLab.Data;
namespace WealthScript
{
    public class SyntheticOptionSymbol : UserStrategyBase
    {
        public override void Initialize(BarHistory bars)
        {
            double strike = Math.Floor(bars.LastValue / 5) * 5;
            DateTime expiry = bars.DateTimes[bars.Count - 1]
                .AddDays(3)
                .NextOptionExpiryDate(bars);
            string symbol = OptionSynthetic.Symbol(
                bars, OptionType.Call, strike, expiry);
            DrawHeaderText(symbol, WLColor.Gold, 12, "Price");
        }
        public override void Execute(BarHistory bars, int idx)
        {
        }
    }
}