/// <summary> /// Test method, displays a sensitivity on heston call and put prices. /// </summary> private void PutCallTest() { Console.WriteLine("Black-Sholes Calls Market Prices"); Console.WriteLine(this.callMarketPrice); Console.WriteLine("Strikes"); Console.WriteLine(this.strike); Console.WriteLine("Maturities"); Console.WriteLine(this.maturity); var x = new Vector() { 3.18344026504981, 0.0427882999286046, 0.644527074840708, -0.659960749691282, 0.0150455464938991, 0.0211747510984717 }; HestonCall hc = new HestonCall(this, x, this.s0); hc.T = .1; hc.rate = this.rate[0]; Console.WriteLine("Strike\tCall\tPut"); for (int z = 200; z < 6500; z += 1000) { hc.K = z; var call = hc.HestonCallPrice(); var put = hc.HestonPutPrice(); var callPut = hc.HestonCallPutPrice(); Console.WriteLine(z + "\t" + callPut[0] + "\t" + callPut[1]); } }
public void Test() { double k = 0.9; double tau = 2.0; double rate = 0.1; double dy = 0.07; double kappa = 2.5; double theta = 0.4; double sigma = 0.2; double s0 = 1.0; double v0 = 0.3; double rho = -0.8; // Calculates the theoretical value of the call. Vector param = new Vector(5); param[0] = kappa; param[1] = theta; param[2] = sigma; param[3] = rho; param[4] = v0; HestonCall hestonCall = new HestonCall(); double fairmatPrice = hestonCall.HestonCallPrice(param, s0, tau, k, rate, dy); double tol = 1e-9; double benchmarkPrice = 0.339537359104676; Console.WriteLine("Theoretical Benchmark Price = " + benchmarkPrice.ToString()); Console.WriteLine("Theoretical Fairmat Price = " + fairmatPrice); Assert.Less(Math.Abs(fairmatPrice - benchmarkPrice), tol); }
/// <summary> /// Calculates a single row of the objective function. Basically /// options with the same maturity and different strikes. /// </summary> /// <param name='context'> /// An object of type <see cref="HestonCall"/> containing the context. /// </param> private void CalculateSingleRow(object context) { CalculateSingleRowWithInterpolation(context); return; HestonCall hc = context as HestonCall; int r = hc.row; for (int c = 0; c < this.callMarketPrice.C; c++) { bool callCondition = this.callMarketPrice[r, c] > s0 * optionThreshold && this.cpmd.CallVolume[r, c] > 0; bool putCondition = this.cpmd.PutPrice[r, c] > s0 * optionThreshold && this.cpmd.PutVolume[r, c] > 0; if (callCondition)//||putCondition) { hc.K = this.strike[c]; var callPut = hc.HestonCallPutPrice(); hc.hestonCallPrice[r, c] = callPut[0]; hc.hestonPutPrice[r, c] = callPut[1]; if (callCondition) { if (HestonCallOptimizationProblem.optimizeRelativeError) { double mkt = pricingMin + this.callMarketPrice[r, c]; double model = pricingMin + hc.hestonCallPrice[r, c]; hc.sum += callWeight[r, c] * Math.Pow((model - mkt) / mkt, 2); } else { hc.sum += callWeight[r, c] * Math.Pow(hc.hestonCallPrice[r, c] - this.callMarketPrice[r, c], 2); } } /* * if (putCondition) * { * if (HestonCallOptimizationProblem.optimizeRelativeError) * { * double mkt = pricingMin + this.cpmd.PutPrice[r, c]; * double model = pricingMin + hc.hestonPutPrice[r, c]; * hc.sum += putWeight[r,c] * Math.Pow((model - mkt) / mkt, 2); * } * else * { * hc.sum += putWeight[r,c]* Math.Pow(hc.hestonPutPrice[r, c] - this.cpmd.PutPrice[r, c], 2); * } * } */ } } return; }
public void Test() { Engine.MultiThread = true; Document doc = new Document(); ProjectROV rov = new ProjectROV(doc); doc.Part.Add(rov); doc.DefaultProject.NMethods.m_UseAntiteticPaths = true; int n_sim = 50000; int n_steps = 512; double strike = 100.0; double tau = 5.0; double rate = 0.1; double dy = 0.07; ModelParameter pStrike = new ModelParameter(strike, "strike"); pStrike.VarName = "strike"; rov.Symbols.Add(pStrike); ModelParameter pRate = new ModelParameter(rate, "rfrate"); pRate.VarName = "rfrate"; rov.Symbols.Add(pRate); AFunction payoff = new AFunction(rov); payoff.VarName = "payoff"; payoff.m_IndependentVariables = 1; payoff.m_Value = (RightValue)("max(x1 - strike ; 0)"); rov.Symbols.Add(payoff); HestonProcess process = new HestonProcess(); process.r = (ModelParameter)rate; process.q = (ModelParameter)dy; process.k = (ModelParameter)2.5; process.theta = (ModelParameter)0.4; process.sigma = (ModelParameter)0.2; process.S0 = (ModelParameter)100.0; process.V0 = (ModelParameter)0.3; StochasticProcessExtendible s = new StochasticProcessExtendible(rov, process); rov.Processes.AddProcess(s); // Set the discounting. RiskFreeInfo rfi = rov.GetDiscountingModel() as RiskFreeInfo; rfi.ActualizationType = EActualizationType.RiskFree; rfi.m_deterministicRF = rate; OptionTree op = new OptionTree(rov); op.PayoffInfo.PayoffExpression = "payoff(v1a)"; op.PayoffInfo.Timing.EndingTime.m_Value = (RightValue)tau; op.PayoffInfo.European = true; rov.Map.Root = op; rov.NMethods.Technology = ETechType.T_SIMULATION; rov.NMethods.PathsNumber = n_sim; rov.NMethods.SimulationSteps = n_steps; ROVSolver solver = new ROVSolver(); solver.BindToProject(rov); solver.DoValuation(-1); if (rov.HasErrors) { Console.WriteLine(rov.m_RuntimeErrorList[0]); } Assert.IsFalse(rov.HasErrors); ResultItem price = rov.m_ResultList[0] as ResultItem; double samplePrice = price.value; double sampleDevSt = price.stdDev / Math.Sqrt((double)n_sim); // Calculates the theoretical value of the call. Vector param = new Vector(5); param[0] = process.k.V(); param[1] = process.theta.V(); param[2] = process.sigma.V(); param[3] = 0.0; param[4] = process.V0.V(); HestonCall hestonCall = new HestonCall(); double thPrice = hestonCall.HestonCallPrice(param, process.S0.V(), tau, strike, rate, dy); Console.WriteLine("Theoretical Price = " + thPrice.ToString()); Console.WriteLine("Monte Carlo Price = " + samplePrice); Console.WriteLine("Standard Deviation = " + sampleDevSt.ToString()); double tol = 4.0 * sampleDevSt; Assert.Less(Math.Abs(thPrice - samplePrice), tol); }
/// <summary> /// Test method, displays a sensitivity on heston call and put prices. /// </summary> private void PutCallTest() { Console.WriteLine("Black-Sholes Calls Market Prices"); Console.WriteLine(this.callMarketPrice); Console.WriteLine("Strikes"); Console.WriteLine(this.strike); Console.WriteLine("Maturities"); Console.WriteLine(this.maturity); var x = new Vector() {3.18344026504981, 0.0427882999286046, 0.644527074840708, -0.659960749691282, 0.0150455464938991, 0.0211747510984717}; HestonCall hc = new HestonCall(this, x, this.s0); hc.T = .1; hc.rate = this.rate[0]; Console.WriteLine("Strike\tCall\tPut"); for (int z = 200; z < 6500; z += 1000) { hc.K = z; var call = hc.HestonCallPrice(); var put = hc.HestonPutPrice(); var callPut = hc.HestonCallPutPrice(); Console.WriteLine(z + "\t" + callPut[0] + "\t" + callPut[1]); } }
/// <summary> /// Calibration objective function. /// </summary> /// <param name='x'> /// The vector of parameters. /// </param> /// <returns> /// Objective function value. /// </returns> public virtual double Obj(DVPLI.Vector x) { double sum = 0; if(Engine.MultiThread && !displayObjInfo) { // Instantiate parallel computation if enabled. List<Task> tl = new List<Task>(); // Context contains both input parameters and outputs. List<HestonCall> context = new List<HestonCall>(); for (int r = 0; r < this.callMarketPrice.R; r++) { if (this.maturity[r] >= this.matBound[0]) { HestonCall hc = new HestonCall(this, x, this.s0); context.Add(hc); hc.T = this.maturity[r]; hc.rate = this.rate[r]; if (HestonConstantDriftEstimator.impliedDividends) hc.dividend = x[Range.End]; else hc.dividend = this.dividendYield[r]; hc.row = r; tl.Add(Task.Factory.StartNew(this.CalculateSingleRow, hc)); } } tsScheduler.WaitTaskList(tl); for (int r = 0; r < tl.Count; r++) sum += context[r].sum; } else { // Sequential version of the code, used when parallel computation is disabled. HestonCall hc = new HestonCall(this, x, this.s0); for (int r = 0; r < this.callMarketPrice.R; r++) { if (this.maturity[r] >= this.matBound[0]) { hc.T = this.maturity[r]; hc.rate = this.rate[r]; if (HestonConstantDriftEstimator.impliedDividends) hc.dividend = x[Range.End]; else hc.dividend = this.dividendYield[r]; hc.row = r; hc.sum = 0; this.CalculateSingleRow(hc); sum += hc.sum; } } var pricingErrors = hc.hestonCallPrice - this.callMarketPrice; if (displayObjInfo) { avgPricingError = 0; for (int r = 0; r < this.callMarketPrice.R; r++) if (this.maturity[r] >= this.matBound[0]) { for (int c = 0; c < this.callMarketPrice.C; c++) { if (this.callMarketPrice[r, c] > s0 * optionThreshold && this.cpmd.CallVolume[r, c] > 0) avgPricingError += Math.Abs(pricingErrors[r, c]); //if (this.cpmd.PutPrice[r, c] > s0 * optionThreshold && this.cpmd.PutVolume[r, c] > 0) // avgPricingError += Math.Abs(pricingErrors[r, c]); } } avgPricingError /= numCall; int RR = Math.Min(12, this.callMarketPrice.R - 1); int CC = Math.Min(12, this.callMarketPrice.C - 1); Console.WriteLine("Mkt Price"); Console.WriteLine(this.callMarketPrice[Range.New(0,RR),Range.New(0,CC)]); Console.WriteLine("Pricing Errors"); Console.WriteLine(pricingErrors[Range.New(0, RR), Range.New(0, CC)]); } objCount++; } //Calculate average distance... sum = Math.Sqrt( sum /this.totalVolume); if (this.useBoundPenalty) sum += this.BoundPenalty(x); if (this.useFellerPenalty) sum +=this.FellerPenalty(x); return sum; }
/// <summary> /// Calculates call put prices for several strikes using controlled interpolation. /// </summary> /// <param name="context"></param> private void CalculateSingleRowWithInterpolation(object context) { HestonCall hc = context as HestonCall; int r = hc.row; hc.sum = 0; // Finds upper extreme for call and put int max_c = 0; for (int c = this.callMarketPrice.C - 1; c > 0; c--) { bool callCondition = this.callMarketPrice[r, c] > s0 * optionThreshold && this.cpmd.CallVolume[r, c] > 0; bool putCondition = this.cpmd.PutPrice != null && this.cpmd.PutPrice[r, c] > s0 * optionThreshold && this.cpmd.PutVolume[r, c] > 0; if (callCondition || putCondition) { max_c = c; break; } } var strikes = new List <double>(); var calls = new List <double>(); var puts = new List <double>(); //Evaluates in strategic points for (int c = 0; c < this.callMarketPrice.C; c++) { bool callCondition = this.callMarketPrice[r, c] > s0 * optionThreshold && this.cpmd.CallVolume[r, c] > 0; bool putCondition = this.cpmd.PutPrice != null && this.cpmd.PutPrice[r, c] > s0 * optionThreshold && this.cpmd.PutVolume[r, c] > 0; if (callCondition || putCondition) { hc.K = this.strike[c]; var callPut = hc.HestonCallPutPrice(); strikes.Add(hc.K); calls.Add(callPut[0]); puts.Add(callPut[1]); if (c == max_c) { break; } c += 1;//skip the subsequent strikes if (c > max_c) { c = max_c; } } } // Builds interpolated call and put values. var callFun = new PFunction((Vector)strikes.ToArray(), (Vector)calls.ToArray()); callFun.m_Function.iType = DVPLUtils.EInterpolationType.SPLINE; var putFun = new PFunction((Vector)strikes.ToArray(), (Vector)puts.ToArray()); putFun.m_Function.iType = DVPLUtils.EInterpolationType.SPLINE; // Evaluates at the requested strikes for (int c = 0; c < this.callMarketPrice.C; c++) { bool callCondition = this.callMarketPrice[r, c] > s0 * optionThreshold && this.cpmd.CallVolume[r, c] > 0; bool putCondition = this.cpmd.PutPrice != null && this.cpmd.PutPrice[r, c] > s0 * optionThreshold && this.cpmd.PutVolume[r, c] > 0; if (callCondition) { hc.hestonCallPrice[r, c] = callFun.Evaluate(this.strike[c]); if (HestonCallOptimizationProblem.optimizeRelativeError) { double mkt = pricingMin + this.callMarketPrice[r, c]; double model = pricingMin + hc.hestonCallPrice[r, c]; hc.sum += callWeight[r, c] * Math.Pow((model - mkt) / mkt, 2); } else { hc.sum += callWeight[r, c] * Math.Pow(hc.hestonCallPrice[r, c] - this.callMarketPrice[r, c], 2); } } if (putCondition) { hc.hestonPutPrice[r, c] = putFun.Evaluate(this.strike[c]); if (HestonCallOptimizationProblem.optimizeRelativeError) { double mkt = pricingMin + this.cpmd.PutPrice[r, c]; double model = pricingMin + hc.hestonPutPrice[r, c]; hc.sum += putWeight[r, c] * Math.Pow((model - mkt) / mkt, 2); } else { hc.sum += putWeight[r, c] * Math.Pow(hc.hestonPutPrice[r, c] - this.cpmd.PutPrice[r, c], 2); } } } return; }
/// <summary> /// Calibration objective function. /// </summary> /// <param name='x'> /// The vector of parameters. /// </param> /// <returns> /// Objective function value. /// </returns> public virtual double Obj(DVPLI.Vector x) { double sum = 0; if (Engine.MultiThread && !displayObjInfo) { // Instantiate parallel computation if enabled. List <Task> tl = new List <Task>(); // Context contains both input parameters and outputs. List <HestonCall> context = new List <HestonCall>(); for (int r = 0; r < this.callMarketPrice.R; r++) { if (this.maturity[r] >= this.matBound[0]) { HestonCall hc = new HestonCall(this, x, this.s0); context.Add(hc); hc.T = this.maturity[r]; hc.rate = this.rate[r]; if (HestonConstantDriftEstimator.impliedDividends) { hc.dividend = x[Range.End]; } else { hc.dividend = this.dividendYield[r]; } hc.row = r; tl.Add(Task.Factory.StartNew(this.CalculateSingleRow, hc)); } } tsScheduler.WaitTaskList(tl); for (int r = 0; r < tl.Count; r++) { sum += context[r].sum; } } else { // Sequential version of the code, used when parallel computation is disabled. HestonCall hc = new HestonCall(this, x, this.s0); for (int r = 0; r < this.callMarketPrice.R; r++) { if (this.maturity[r] >= this.matBound[0]) { hc.T = this.maturity[r]; hc.rate = this.rate[r]; if (HestonConstantDriftEstimator.impliedDividends) { hc.dividend = x[Range.End]; } else { hc.dividend = this.dividendYield[r]; } hc.row = r; hc.sum = 0; this.CalculateSingleRow(hc); sum += hc.sum; } } var pricingErrors = hc.hestonCallPrice - this.callMarketPrice; if (displayObjInfo) { avgPricingError = 0; for (int r = 0; r < this.callMarketPrice.R; r++) { if (this.maturity[r] >= this.matBound[0]) { for (int c = 0; c < this.callMarketPrice.C; c++) { if (this.callMarketPrice[r, c] > s0 * optionThreshold && this.cpmd.CallVolume[r, c] > 0) { avgPricingError += Math.Abs(pricingErrors[r, c]); } //if (this.cpmd.PutPrice[r, c] > s0 * optionThreshold && this.cpmd.PutVolume[r, c] > 0) // avgPricingError += Math.Abs(pricingErrors[r, c]); } } } avgPricingError /= numCall; int RR = Math.Min(12, this.callMarketPrice.R - 1); int CC = Math.Min(12, this.callMarketPrice.C - 1); Console.WriteLine("Mkt Price"); Console.WriteLine(this.callMarketPrice[Range.New(0, RR), Range.New(0, CC)]); Console.WriteLine("Pricing Errors"); Console.WriteLine(pricingErrors[Range.New(0, RR), Range.New(0, CC)]); } objCount++; } //Calculate average distance... sum = Math.Sqrt(sum / this.totalVolume); if (this.useBoundPenalty) { sum += this.BoundPenalty(x); } if (this.useFellerPenalty) { sum += this.FellerPenalty(x); } return(sum); }
public static void Main(string[] args) { int Caso = 1; if (Caso == 0) { InterestRateMarketData MData = InterestRateMarketData.FromFile("../../../TestData/InterestRatesModels/05052009-EU.xml"); CallPriceMarketData test = CallPriceMarketData.FromFile("../../../TestData/Heston/05052009-SX5E-HestonData.xml"); EquityCalibrationData CalData = new EquityCalibrationData(test, MData); Matrix CallMarketPrice = (Matrix)test.CallPrice; Vector Maturity = (Vector)test.Maturity; Vector Strike = (Vector)test.Strike; Vector DividendYield = (Vector)test.DividendYield; Vector Drift = CalData.Rate - CalData.DividendYield; Vector Rate = CalData.Rate; double u, kappa, theta, sigma, rho, v0, s0, r, q, T, K, val; u = 1.0; kappa = 19.4; theta = 0.235; sigma = 0.00500999; rho = -0.96; v0 = 0.664; s0 = 3872.15; r = -0.0867303549580581; q = 0; T = 0.50; K = 6000; Vector MatBound = new Vector(2); Vector StrikeBound = new Vector(2); MatBound[0] = 0.0; MatBound[1] = 2.0; StrikeBound[0] = 0.7; StrikeBound[1] = 1.3; Matrix Volatility = new Matrix(test.CallPrice.R, test.CallPrice.C); HestonCallOptimizationProblem HP = new HestonCallOptimizationProblem(CallMarketPrice, Maturity, Strike, Rate, DividendYield, test.S0, MatBound, StrikeBound, Volatility); Complex Cval, Cu; Cu = u - Complex.I; HestonCall hc = new HestonCall(HP); Cval = hc.phi(u, kappa, theta, sigma, rho, s0, v0, r, T); Console.WriteLine("phi1 = {0}", Cval); Cval = hc.phi(Cu, kappa, theta, sigma, rho, s0, v0, r, T); Console.WriteLine("phi2 = {0}", Cval); val = hc.IntegrandFunc(u, kappa, theta, sigma, rho, s0, v0, r, q, T, K); Console.WriteLine("IntFunc = {0}", val); Vector x = new Vector(5); x[0] = kappa; x[1] = theta; x[2] = sigma; x[3] = rho; x[4] = v0; DateTime T1, T2; TimeSpan ElapsedTime; double Time, Time2, Time3; T1 = DateTime.Now; val = hc.HestonCallPrice(x, s0, T, K, r, q); T2 = DateTime.Now; ElapsedTime = T2 - T1; Time = (double)ElapsedTime.Milliseconds; Time2 = (double)ElapsedTime.Seconds; Console.WriteLine("Price = {0}", val); Console.WriteLine("Elapsed Time = {0}", Time2 + Time / 1000); int NProve = 10; int NPassi = 1000; double val2; Random CasNum = new Random(); for (int i = 0; i < NProve; i++) { for (int j = 0; j < 5; j++) { val2 = ((double)CasNum.Next(0, NPassi)) / ((double)NPassi); x[j] = HP.Bounds.Lb[j] + (HP.Bounds.Ub[j] - HP.Bounds.Lb[j]) * val2; } Console.Write("Trial {0} x = " + x.ToString(), i + 1); T1 = DateTime.Now; val = HP.Obj(x); T2 = DateTime.Now; ElapsedTime = T2 - T1; Time = (double)ElapsedTime.Milliseconds; Time2 = (double)ElapsedTime.Seconds; Time3 = (double)ElapsedTime.Minutes; Console.WriteLine(" Time = {0}' {1}'' Val = {2}", Time3, Time2 + Time / 1000, val); } } if (Caso == 1) { TestHestonCallEstimation NewTest = new TestHestonCallEstimation(); bool Result = NewTest.Run(); } }