Code: Select all
using System;
using System.Drawing;
using System.Linq;
namespace PowerLanguage
{
namespace Function
{
public sealed class OptionDelta : FunctionSimple<System.Double>
{
public OptionDelta(CStudyControl _master) : base(_master) { }
public OptionDelta(CStudyControl _master, int _ds) : base(_master, _ds) { }
public double underlyingPrice;
public double underlyingVolatilty;
public double riskFreeRate;
public double dividendYield;
protected override System.Double CalcBar()
{
DateTime expDate = Bars.Info.Expiration;
bool isCallOption = Bars.Info.OptionType == OptionType.Call;
double strikePrice = Bars.Info.StrikePrice;
int daysToExpiration = (int)(expDate.Date - DateTime.Now.Date).TotalDays;
double yearsToExpiration = (double)daysToExpiration/(double)365;
if (isCallOption)
{
return this.getNormsDistribution(this.dOne(this.underlyingPrice, strikePrice, yearsToExpiration, this.riskFreeRate, this.underlyingVolatilty, this.dividendYield));
}
else
{
return this.getNormsDistribution(this.dOne(this.underlyingPrice, strikePrice, yearsToExpiration, this.riskFreeRate, this.underlyingVolatilty, this.dividendYield)) - 1;
}
}
private double dOne(double underlyingPrice, double strikePrice, double yearsToExpiration, double riskFreeRate, double underlyingVolatility, double dividendYield)
{
return (Math.Log(underlyingPrice / strikePrice) + (riskFreeRate - dividendYield + 0.5 * Math.Pow(underlyingVolatility, 2)) * yearsToExpiration) / (underlyingVolatility * Math.Sqrt(yearsToExpiration));
}
private double getNormsDistribution(double x)
{
const double b1 = 0.319381530;
const double b2 = -0.356563782;
const double b3 = 1.781477937;
const double b4 = -1.821255978;
const double b5 = 1.330274429;
const double p = 0.2316419;
const double c = 0.39894228;
if (x >= 0.0)
{
double t = 1.0 / (1.0 + p * x);
return (1.0 - c * Math.Exp(-x * x / 2.0) * t * (t * (t * (t * (t * b5 + b4) + b3) + b2) + b1));
}
else
{
double t = 1.0 / (1.0 - p * x);
return (c * Math.Exp(-x * x / 2.0) * t * (t * (t * (t * (t * b5 + b4) + b3) + b2) + b1));
}
}
}
}
}
And I call this function like so in my gamma scalping signal, where the option is data source 2.
Code: Select all
private OptionDelta optionDelta;
protected override void Create() {
this.optionDelta = new OptionDelta(this, 2);
}
protected override void StartCalc() {
this.optionDelta.dividendYield = this.dividendYield;
this.optionDelta.riskFreeRate = this.riskFreeRate;
}
protected override void CalcBar(){
double underlyingPrice = BarsOfData(1).Close.Value;
this.optionDelta.underlyingPrice = underlyingPrice;
this.optionDelta.underlyingVolatilty = this.underlyingVolatility;
double optionDelta = this.optionDelta[0];
....
}
I do have a version of my signal where I calculate the underlyingVolatility within the signal (passing the underlying daily time series as another data source) but as I have my primary data series set for every 1 second I would consume all of my allowed IB historical data before I could launch, so I just check the chart each day and update the input if needed.
The delta value generated matches what I find in various online option calculators but are off by a point or two compared to what IB shows in the option chain, so apparently we have different inputs somehow.
Enjoy, and let me know if you find a way to improve it.
Bests,
Carl