using System.Collections.Generic;
public static class Globals {
public static readonly double[] moneyness = { 50, 60, 70, 75, 80, 85, 87.5, 90, 92.5, 95, 97.5, 100, 102.5, 105, 107.5, 110, 115, 120, 125};
public static readonly double deltaLowerLimit = -1.644;
public static readonly double deltaUpperLimit = 1.644;
public static SortedDictionary<double, double>
sviVol( Dictionary<string, double> sviparams ) {
SortedDictionary<double, double>resultMap = new SortedDictionary<double, double>();
double spot = sviparams["Spot"];
double _vt = sviparams["CATM"];
double _psit = sviparams["CSkew"];
double _crvt = sviparams["CCurve"];
double _pt = sviparams["CPutWing"];
double _cs = sviparams["CCallSlope"];
double _ch = sviparams["CCallHeight"];
double _texp = sviparams["TExp"];
double forward = sviparams["Forward"];
foreach (double moneyness in Globals.moneyness ) {
double strike = moneyness * spot / 100;
double k = Math.Log(strike/forward) / _vt / Math.Sqrt( _texp );
double omega = _vt * _vt * _texp;
double _b1 = Math.Sqrt(omega) / 2.0 * (_cs + _pt);
double _rho1 = (_cs - _pt) / (_cs + _pt);
double bet_a1 = _rho1 - 2 * _psit * Math.Sqrt(omega) / _b1;
double alph_a1 = Math.Sign(bet_a1) * Math.Sqrt( 1 / bet_a1 / bet_a1 - 1);
double numerator = _b1 * alph_a1 * alph_a1 * Math.Sign(alph_a1);
double denom1 = 2 * Math.Sqrt(omega * _texp) * Math.Pow((1 + alph_a1 * alph_a1),1.5);
double denom2 = _crvt + _psit * _psit / Math.Sqrt(omega * _texp);
double _m1 = numerator / denom1 / denom2;
double _sigma1 = alph_a1 * _m1;
double _a1 = omega - _b1 * ( Math.Sqrt(_m1*_m1 + _sigma1*_sigma1) - _rho1 * _m1);
total_double = _a1 + _b1 *( _rho1*(k-_m1) + Math.Sqrt( (k-_m1)*(k-_m1) + _sigma1 * _sigma1 ) );
double _b2 = Math.Sqrt(omega) / 2.0 * (_cs + _ch);
double _rho2 = (_cs - _ch) / (_cs + _ch);
double bet_a2 = _rho2 - 2 * _psit * Math.Sqrt(omega) / _b2;
double alph_a2 = Math.Sign(bet_a2) * Math.Sqrt( 1 / bet_a2 / bet_a2 - 1);
double numerator = _b2 * alph_a2 * alph_a2 * Math.Sign(alph_a2);
double denom1 = 2 * Math.Sqrt(omega * _texp) * Math.Pow((1 + alph_a2 * alph_a2),1.5);
double denom2 = _crvt + _psit * _psit / Math.Sqrt(omega * _texp );
double _m2 = numerator / denom1 / denom2;
double _sigma2 = alph_a2 * _m2;
double _a2 = omega - _b2 * (Math.Sqrt(_m2*_m2 + _sigma2*_sigma2) - _rho2 * _m2);
total_double = _a2 + _b2 *( _rho2*(k-_m2) + Math.Sqrt( (k-_m2)*(k-_m2) + _sigma2 * _sigma2 ) );
double d = Math.Sqrt( total_double / _texp );
if ( d < 0.0001 ) d = 0.0001;
double d1 = ( Math.Log( forward / strike ) - 0.5 * d * d * _texp ) / ( d * Math.Sqrt(_texp) );
if ( d1 > Globals.deltaLowerLimit && d1 < Globals.deltaUpperLimit ) {
resultMap[ Math.Round( strike ) ] = d;
resultMap[ Math.Round( strike ) ] = 0;
public static SortedDictionary<double, double>
orcVol( Dictionary<string, double> orcparams ) {
SortedDictionary<double, double>resultMap = new SortedDictionary<double, double>();
double spot = orcparams["Spot"];
double _time = orcparams["TExp"];
double _fwdPx = orcparams["Forward"];
double _refVol = orcparams["OrcATM"];
double _refPx = orcparams["OrcRefPrice"];
double _refSlope = orcparams["OrcATMSkew"];
double _callCrv = orcparams["OrcCallCrv"];
double _putCrv = orcparams["OrcPutCrv"];
double _upCO = orcparams["OrcUpCutOff"];
double _downCO = orcparams["OrcDownCutOff"];
double _downSm = orcparams["OrcDownSM"];
double _upSm = orcparams["OrcUpSM"];
foreach (double moneyness in Globals.moneyness ) {
double strike = moneyness * spot / 100;
double curVol = (_refVol - ((_vcr * _ssr * (_fwdPx - _refPx)) / _refPx));
double curSlope = (_refSlope - ((_scr * _ssr * (_fwdPx - _refPx)) / _refPx));
double F = Math.Pow(_fwdPx, (_ssr / 100)) * Math.Pow(_refPx, (1 - (_ssr / 100)));
double X = Math.Log(strike / F);
if ( timedep && _time > 0 )
double z = F * Math.Exp(0.6 * curVol * Math.Sqrt(_time) + curVol * curVol * _time);
X = Math.Log( strike / z ) / Math.Sqrt(_time);
double z = F * ( 1 + 0.05 * Math.Sqrt( _time ) );
X = ( strike / z - 1 ) / Math.Sqrt(_time);
d = curVol + curSlope * X + _callCrv * X * X;
if (_upCO * (1 + _upSm) < X) {
d = curVol + _upCO * (2 + _upSm) * (curSlope / 2) + (1 + _upSm)
* _callCrv * _upCO * _upCO;
d = curVol - (1 + 1 / _upSm) * _callCrv * _upCO * _upCO
- ((curSlope * _upCO) / (2 * _upSm));
d = d + (1 + 1 / _upSm) * (2 * _callCrv * _upCO + curSlope) * X;
d = d - ((_callCrv / _upSm) + (curSlope / (2 * _upCO * _upSm)))
d = curVol + curSlope * X + _putCrv * X * X;
if (_downCO * (1 + _downSm) > X) {
d = curVol + _downCO * (2 + _downSm) * (curSlope / 2) + (1
+ _downSm) * _putCrv * _downCO * _downCO;
d = curVol - (1 + 1 / _downSm) * _putCrv * _downCO * _downCO
- ((curSlope * _downCO) / (2 * _downSm));
d = d + (1 + 1 / _downSm) * (2 * _putCrv * _downCO + curSlope)
d = d - ((_putCrv / _downSm) + (curSlope / (2 * _downCO
if ( d < 0.0001 ) d = 0.0001;
double d1 = ( Math.Log( _fwdPx / strike ) - 0.5 * d * d * _time ) / ( d * Math.Sqrt(_time) );
if ( d1 > Globals.deltaLowerLimit && d1 < Globals.deltaUpperLimit ) {
resultMap[ Math.Round( strike ) ] = d;
resultMap[ Math.Round( strike ) ] = 0;
public static SortedDictionary<double, double>
getVol(string model, Dictionary<string, double> volparams ) {
if ( model == "OrcIndex" ) {
var orcparams = new Dictionary<string, double>();
orcparams["OrcATM"] = volparams["OrcATMIndex"];
orcparams["OrcRefPrice"] = volparams["OrcRefPriceIndex"] ;
orcparams["OrcATMSkew"] = volparams["OrcATMSkewIndex"] ;
orcparams["OrcCallCrv"] = volparams["OrcCallCrvIndex"] ;
orcparams["OrcPutCrv"] = volparams["OrcPutCrvIndex"] ;
orcparams["OrcUpCutOff"] = volparams["OrcUpCutOffIndex"] ;
orcparams["OrcDownCutOff"]= volparams["OrcDownCutOffIndex"] ;
orcparams["OrcDownSM"] = volparams["OrcDownSMIndex"] ;
orcparams["OrcUpSM"] = volparams["OrcUpSMIndex"] ;
orcparams["TExp"] = volparams["TExp"] ;
orcparams["Forward"] = volparams["Forward"] ;
orcparams["Spot"] = volparams["Spot"] ;
return orcVol( orcparams );
} else if ( model == "Orc" ) {
return orcVol( volparams );
} else if ( model == "SVIIndex" ) {
var sviparams = new Dictionary<string, double>();
sviparams["CATM"] = volparams["SVICATMIndex"];
sviparams["CSkew"] = volparams["SVICSkewIndex"];
sviparams["CCurve"] = volparams["SVICCurveIndex"];
sviparams["CPutWing"] = volparams["SVICPutWingIndex"];
sviparams["CCallSlope"] = volparams["SVICCallSlopeIndex"];
sviparams["CCallHeight"]= volparams["SVICCallHeightIndex"];
sviparams["TExp"] = volparams["TExp"];
sviparams["Forward"] = volparams["Forward"];
sviparams["Spot"] = volparams["Spot"] ;
return sviVol( sviparams );
} else if ( model == "SVI" ) {
var sviparams = new Dictionary<string, double>();
sviparams["CATM"] = volparams["SVICATM"];
sviparams["CSkew"] = volparams["SVICSkew"];
sviparams["CCurve"] = volparams["SVICCurve"];
sviparams["CPutWing"] = volparams["SVICPutWing"];
sviparams["CCallSlope"] = volparams["SVICCallSlope"];
sviparams["CCallHeight"]= volparams["SVICCallHeight"];
sviparams["TExp"] = volparams["TExp"];
sviparams["Forward"] = volparams["Forward"];
sviparams["Spot"] = volparams["Spot"] ;
return sviVol( sviparams );
return new SortedDictionary<double, double>();
public static void Main()
var orcparams = new Dictionary<string, double>();
orcparams["OrcATM"] = 0.12;
orcparams["OrcRefPrice"] = 2300 ;
orcparams["OrcATMSkew"] = -0.04;
orcparams["OrcCallCrv"] = -0.04 ;
orcparams["OrcPutCrv"] = -0.04;
orcparams["OrcUpCutOff"] = 0.75;
orcparams["OrcDownCutOff"]= -0.75;
orcparams["OrcDownSM"] = 5;
orcparams["OrcUpSM"] = 5;
orcparams["TExp"] = 0.25;
orcparams["Forward"] = 2300;
orcparams["Spot"] = 2300;
SortedDictionary<double, double> a = getVol( "Orc", orcparams );
foreach (KeyValuePair<double, double> kvp in a)
Console.WriteLine("Key = {0}, Value = {1}", kvp.Key, kvp.Value);