【C#】 25. 根据Option组成的投资组合的payoff,识别组成成分

今天终究做了1个很久之前就想完成的option利用!

假定现在有1个全部由Option构成的投资组合,这些option的underlying都是同1个股票,有相同的maturity

在Excel中写个函数,它可以根据portfolio在不同underlying price时的Payoff来辨认投资组合中各个option组成。


上图左侧的表格就是Input,Payoff图在其下方(strangle);而右侧的表格就是计算得到的结果,我写的这个函数名字为 OpTypestrikeContractNum


using System; using System.Collections.Generic; using System.Linq; using System.Text; using ExcelDna.Integration; using FinMktReverseEngineering; using Excel = Microsoft.Office.Interop.Excel; using System.Runtime.InteropServices; using Microsoft.solverFoundation.Services; using Microsoft.solverFoundation.solvers; namespace OptionFunctions {     //Solver Class for calculate the contract number for options     public class CSolver     {         private double[] interpolatedStockPrice;         private double[] interpolatedTargetPayoffs;         private Option[] options;         private int optionNum;         //Constructor         public CSolver(Option[] Options,double[] InterpolatedTargetPayoffs,double[] InterpolatedStockPrice)         {             this.options = Options;             this.interpolatedTargetPayoffs = InterpolatedTargetPayoffs;             this.interpolatedStockPrice = InterpolatedStockPrice;             this.optionNum = options.Length;         }         //Target Function         public double TargetFunction(double[] ContractNum)         {             double sum2OfDiff=0.0;             double sum2OfContractNum=0.0;             double totalPayoff;             for (int i = 0; i < interpolatedStockPrice.Length; i++)             {                 totalPayoff = 0.0;                 for (int j = 0;  j < options.Length;  j++)                 {                     totalPayoff+= options[j].Payoff(interpolatedStockPrice[i]) * ContractNum[j];                     sum2OfContractNum += Math.Pow(ContractNum[j]-Math.Round(ContractNum[j],0),2);  //Very important! To avoid trivial answers!!!                 }                 sum2OfDiff += Math.Pow(interpolatedTargetPayoffs[i] - totalPayoff,2);   //Residuals^2             }             return sum2OfDiff+sum2OfContractNum;         }         //Solver         internal double[] IndidualSolve()         {             var hls = new HybridLocalSearchSolver();             int[] contractNumID = new int[optionNum];             double[] results=new double[optionNum];             //Add variable in the solver             for (int i = 0; i < contractNumID.Length; i++)             {                 hls.AddVariable(out contractNumID[i],                    Microsoft.solverFoundation.Common.Rational.NegativeInfinity,                    Microsoft.solverFoundation.Common.Rational.PositiveInfinity,                      false);               }             //Solving             hls.AddGoal(hls.CreateNaryFunction(TargetFunction,contractNumID));//目标函数最小化             var hlsr = hls.solve(new HybridLocalSearchParameters());             //Set results             for (int i = 0; i < results.Length; i++)             {                 results[i] = hlsr.GetValue(contractNumID[i]);             }             return results;        }     }         public class OptionFunctions         {             //Function OptionPrice             [ExcelFunction(Description = Exact solution for European option,Category = Option Functions)]             public static double OptionPrice([ExcelArgument(Description = @Call (C) or a put (P))]string optionType,                [ExcelArgument(Description = @Stock)]double underlying,[ExcelArgument(Description = @Risk-free rate)]double interestRate,                 [ExcelArgument(Description = @Volatility)]double volatility,[ExcelArgument(Description = @Strike price)]double strikePrice,                  [ExcelArgument(Description = @Time to maturity(in years))]double timetomaturity,[ExcelArgument(Description = @Cost of carry)]double costOfCarry)             {                 // Basic validation -                 if (underlying <= 0.0 || volatility <= 0.0 || timetomaturity <= 0.0 || strikePrice <= 0.0)                 {                     // Exception will be returned to Excel as #VALUE.                     throw new ArgumentException();                 }                 Option o = new Option();                 o.otyp = optionType;                 o.r = interestRate;                 o.sigma = volatility;                 o.K = strikePrice;                 o.T = timetomaturity;                 o.b = costOfCarry;                 return o.Price(underlying);             }             //Function OptionPriceGreeks             [ExcelFunction(Description = Compute exact solution for a European option,and returns price and greeks as a two-column,                 + six-row array with names and values,Category = Option Functions)]             public static object[,] OptionPriceGreeks([ExcelArgument(Description = @Call (C) or a put (P))]string optionType,                [ExcelArgument(Description = @Value of the underlying stock)]double underlying,                  [ExcelArgument(Description = @Time to maturity(years))]double timetomaturity,[ExcelArgument(Description = @Cost of carry)]double costOfCarry)             {                 // Basic validation                 if (underlying <= 0.0 || volatility <= 0.0 || timetomaturity <= 0.0 || strikePrice <= 0.0)                 {                     // Exception will be returned to Excel as #VALUE.                     throw new ArgumentException();                 }                 Option o = new Option();                 o.otyp = optionType;                 o.r = interestRate;                 o.sigma = volatility;                 o.K = strikePrice;                 o.T = timetomaturity;                 o.b = costOfCarry;                 return new object[7,2]{             {Price,o.Price(underlying)},            {Delta,o.Delta(underlying)},            {Gamma,o.Gamma(underlying)},            {Vega,o.Vega(underlying)},            {Theta,o.Theta(underlying)},            {Rho,o.Rho(underlying)},            {Coc,o.Coc(underlying)}             };             }             //Function Payoff             [ExcelFunction(Description = Payoff for European option,] Payoff(                 [ExcelArgument(Description = @Call (C) or a put (P))]object[] optionType,                [ExcelArgument(Description = @Strike price)]object[] strikes)             {                 int len=optionType.Length;                 //Option and Stock Price at T array <span style=white-space:pre> </span>        Option[] options;                 double[] st;                  double[] payoffs;                    options= new Option[len];                 st = new double[len + 2];                 payoffs=new double[len+2];                 //Initiate the first element st=0.0                 st[0] = 0.0;                 st[len + 1] = (double)strikes[len⑴]+10.0;    //The last ST is last strike +10.0                 for (int i = 0; i < len; i++) <span style=white-space:pre> </span>    { <span style=white-space:pre> </span>        options[i]=new Option();                     options[i].otyp=(string)optionType[i];                     options[i].K=(double)strikes[i];                     st[i + 1] = (double)strikes[i]; //Set st as strike price                 }                 //Payoffs at different strockPrice                 payoffs = coptionPayoff.OptionPayoff(st,options);                 //Return result: St and corresponding Payoff                     object[,] result;                 result = new object[len+2,2];                 for (int i = 0; i < len+2; i++) <span style=white-space:pre> </span>    { <span style=white-space:pre> </span>        result[i,0]=(double)st[i];                     result[i,1]=(double)payoffs[i]; <span style=white-space:pre> </span>    }                 return result;             }             //Return corresponding option contract number by minimizing square of sum of the payoff difference              //ST:       0, 100,   110,   120,   140,   150             //Payoff:  0,  10,    20,    10,    10                [ExcelFunction(Description = Return corresponding option contract number by minimizing square of sum of the payoff difference ,] OpTypestrikeContractNum(                 [ExcelArgument(Description = @Stock price at maturity)]object[] StockPrices,                [ExcelArgument(Description = @Target payoffs)]object[] TargetPayoffs)             {                 int obsNum = StockPrices.Length;    //input number of stock price and target payoffs                 int optionNumNeeded = 2*(obsNum - 2);   //option number needed                 int numAfterInterpolation = obsNum * 2 - 2;                 double[] ContractNum;     //1st col: Type; 2nd col: Strike; 3rd col: ContractNum                 double[] interpolatedStockPrice;                     double[] interpolatedTargetPayoffs;                 Option[] options;                                  //Initiate the needed options                 options = new Option[optionNumNeeded];                 ContractNum = new double[optionNumNeeded];                 interpolatedStockPrice = new double[numAfterInterpolation]; //10                 interpolatedTargetPayoffs = new double[numAfterInterpolation];  //10                                  //Set options strike prices                 for (int i = 0; i < obsNum⑵; i++) //0,1,2,3                 {                     //Set the Option Instances                     options[i] = new Option();                     options[i].otyp = C;                     options[i].K = (double)StockPrices[i + 1];                     options[i + optionNumNeeded / 2] = new Option();                     options[i + optionNumNeeded / 2].otyp = P;                     options[i + optionNumNeeded / 2].K = (double)StockPrices[i + 1];                     //Set certain interpolated stock prices                     interpolatedStockPrice[i*2]=(double)StockPrices[i]; //0,4,6                     interpolatedTargetPayoffs[i*2]=(double)TargetPayoffs[i];                 }                 //Set the last two elements in the interpolation                 interpolatedStockPrice[numAfterInterpolation - 2] = (double)StockPrices[obsNum - 2];                 interpolatedStockPrice[numAfterInterpolation - 1] = (double)StockPrices[obsNum - 1];                 interpolatedTargetPayoffs[numAfterInterpolation - 2] = (double)TargetPayoffs[obsNum - 2];                 interpolatedTargetPayoffs[numAfterInterpolation - 1] = (double)TargetPayoffs[obsNum - 1];                 //Interpolation                 for (int i = 1; i < optionNumNeeded; i += 2)                 {                     interpolatedStockPrice[i] = 0.5 * (interpolatedStockPrice[i - 1] + interpolatedStockPrice[i + 1]);                     interpolatedTargetPayoffs[i] = 0.5 * (interpolatedTargetPayoffs[i - 1] + interpolatedTargetPayoffs[i + 1]);                 }                 //Solver                 CSolver solver = new CSolver(options,interpolatedTargetPayoffs,interpolatedStockPrice);                 ContractNum = solver.IndidualSolve();                 //result => 1st column is option type; 2nd column is strike; 3rd column is contract number                 object[,] result = new object[optionNumNeeded,3];                 for (int i = 0; i < optionNumNeeded; i++)                 {                     result[i,0] = (string)options[i].otyp;                     result[i,1] = (double)options[i].K;                     result[i,2] =(double) ContractNum[i];                 }                 return result;             }         }     }


之前1直困惑我的问题是,当用许多option(不同的K)去求解时,会出现很多小数contract number的问题,最后终究想到了1个办法,那就是把它作为目标函数的1部份写进去!结果成功!!!好爽!!!

例如,1个Strangle+Put:



相关文章

统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...
统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...
前言 之前做了微信登录,所以总结一下微信授权登录并获取用户...
FastAdmin是我第一个接触的后台管理系统框架。FastAdmin是一...
之前公司需要一个内部的通讯软件,就叫我做一个。通讯软件嘛...
统一支付是JSAPI/NATIVE/APP各种支付场景下生成支付订单,返...