程式

使用 C# 中的極端優化進行風險平價投資組合優化

  • September 12, 2012

我正在嘗試使用極端優化常式在 C# 中創建風險平價投資組合。

在我購買它們之前,我主要是在試穿它們,看看我是否喜歡它們(我是學生,所以錢很緊)。

我的想法是實施這種稱為風險平價的新型投資組合優化。它基本上說,為了使您的投資組合多樣化,您應該為其每個組成部分賦予相同的風險。

執行時出現空錯誤np1.Solve(),我不明白為什麼。我以為其他的一切都是由極限優化計算出來的。

  1. 我究竟做錯了什麼?
  2. 有沒有一種我不知道的更快的方法來進行這種優化?
  3. 如果你不知道 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));

       }
   }
}

引用自:https://quant.stackexchange.com/questions/3815