程式
使用 C# 中的極端優化進行風險平價投資組合優化
我正在嘗試使用極端優化常式在 C# 中創建風險平價投資組合。
在我購買它們之前,我主要是在試穿它們,看看我是否喜歡它們(我是學生,所以錢很緊)。
我的想法是實施這種稱為風險平價的新型投資組合優化。它基本上說,為了使您的投資組合多樣化,您應該為其每個組成部分賦予相同的風險。
執行時出現空錯誤
np1.Solve()
,我不明白為什麼。我以為其他的一切都是由極限優化計算出來的。
- 我究竟做錯了什麼?
- 有沒有一種我不知道的更快的方法來進行這種優化?
- 如果你不知道 EO 庫,但可以用其他東西來實現它,你能否就如何解決這個問題發表評論?
順便說一下,投資組合建構的詳細資訊在距離函式的註釋中,以防您感興趣。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Extreme.Statistics; using Extreme.Mathematics; using Extreme.Mathematics.Optimization; namespace TestingRiskParityOptimization { class Program { static void Main(string[] args) { NonlinearProgram np1 = new NonlinearProgram(2); Func<Vector, double> distance = DistanceFunction; np1.ObjectiveFunction = distance; np1.InitialGuess = Vector.CreateConstant(2, 1.0 / ((double)2)); np1.AddNonlinearConstraint(x => x[0] + x[1], ConstraintType.GreaterThanOrEqual, 0); Vector solution = np1.Solve(); Console.WriteLine("Solution: {0:F6}", solution); Console.WriteLine("Optimal value: {0:F6}", np1.OptimalValue); Console.WriteLine("# iterations: {0}", np1.SolutionReport.IterationsNeeded); Console.Write("Press Enter key to exit..."); Console.ReadLine(); } private static double DistanceFunction(Vector Weights) { Matrix Sigma = Matrix.Create(new double[,] { {0.1, 0.2}, {0.2, 0.4} }); // if VarP = Weights' * CovarMatrix * Weights and VolP = sqrt(VarP) // Then the marginal contribution to risk of an asset is the i-th number of // Sigma*Weights*VolP // And thus the contribution to risk of an asset is simply Weights . (Sigma*Weights/VarP) // we need to find weights such that Weights (i) * Row(i) of (Sigma*Weights/VarP) = 1/N // that is we want to minimize the distance of row vector (Weights (i) * Row(i) of (Sigma*Weights/VarP)) and vector 1/N double Variance = Vector.DotProduct(Weights, Sigma * Weights); Vector Beta = Sigma * Weights / Variance; for (int i = 0; i < Beta.Length; i++) { // multiplies row of beta by weight to find the percent contribution to risk Beta[i] = Weights[i] * Beta[i]; } Vector ObjectiveVector = Vector.CreateConstant(Weights.Length, 1.0 / ((double)Weights.Length)); Vector Distance = Vector.Subtract(Beta, ObjectiveVector); return Math.Sqrt(Vector.DotProduct(Distance, Distance)); } } }
如果有人感興趣,我使用 Nelder-Mead 的算法解決了這個問題。性能可能會更好,但我不想再浪費時間了。
這是最終的解決方案:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using Extreme.Statistics; using Extreme.Mathematics; using Extreme.Mathematics.Optimization; namespace TestingRiskParityOptimization { class Program { static void Main(string[] args) { Func<Vector, double> distance = DistanceFunction; NelderMeadOptimizer nm1 = new NelderMeadOptimizer(); nm1.ObjectiveFunction = DistanceFunction; nm1.ContractionFactor = 0.5; nm1.ExpansionFactor = 2; nm1.ReflectionFactor = -2; nm1.SolutionTest.AbsoluteTolerance = 1e-15; nm1.InitialGuess = Vector.CreateConstant(2, 1.0 / ((double)2)); nm1.ExtremumType = ExtremumType.Minimum; Vector solution = nm1.FindExtremum(); Console.WriteLine("Solution: {0:F6}", solution); Console.WriteLine(" Estimated error: {0}", nm1.EstimatedError); Console.WriteLine(" # iterations: {0}", nm1.IterationsNeeded); Console.WriteLine(" # function evaluations: {0}", nm1.EvaluationsNeeded); Console.Write("Press Enter key to exit..."); Console.ReadLine(); } private static double DistanceFunction(Vector Weights) { Matrix Sigma = Matrix.Create(new double[,] { {0.1, 0.23}, {0.23, 0.7} }); // if VarP = Weights' * CovarMatrix * Weights and VolP = sqrt(VarP) // Then the marginal contribution to risk of an asset is the i-th number of // Sigma*Weights*VolP // And thus the contribution to risk of an asset is simply Weights . (Sigma*Weights/VarP) // we need to find weights such that Weights (i) * Row(i) of (Sigma*Weights/VarP) = 1/N // that is we want to minimize the distance of row vector (Weights (i) * Row(i) of (Sigma*Weights/VarP)) and vector 1/N double Variance = Vector.DotProduct(Weights, Sigma * Weights); Vector Beta = Sigma * Weights / Variance; for (int i = 0; i < Beta.Length; i++) { // multiplies row of beta by weight to find the percent contribution to risk Beta[i] = Weights[i] * Beta[i]; } Vector ObjectiveVector = Vector.CreateConstant(Weights.Length, 1.0 / ((double)Weights.Length)); Vector Distance = Vector.Subtract(Beta, ObjectiveVector); return Math.Sqrt(Vector.DotProduct(Distance, Distance)); } } }