5 votos

Optimización de la cartera de riesgo-paridad mediante la optimización extrema en C#

Estoy intentando crear una cartera de riesgo-paridad en C# utilizando las rutinas de Optimización Extrema.

Principalmente los estoy probando para ver si me gustan o no antes de comprarlos (soy estudiante así que el dinero es escaso).

Mi idea era poner en práctica este nuevo tipo de optimización de la cartera llamado riesgo-paridad. Básicamente dice que para diversificar tu cartera debes dar igual riesgo a cada uno de sus componentes.

Estoy recibiendo un error nulo al ejecutar np1.Solve() y no entiendo por qué. Pensaba que todo lo demás lo calculaba la Optimización Extrema.

  1. ¿Qué estoy haciendo mal?

  2. ¿Hay alguna forma más rápida de hacer esta optimización que yo desconozca?

  3. Si no conoces las Bibliotecas EO, pero podrías implementar esto con algo más, ¿podrías por favor dejar un comentario sobre cómo harías para resolver esto?

Por cierto, los detalles sobre la construcción de la cartera están en los comentarios de la función de distancia, por si te interesa.

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));

        }
    }
}

2voto

Ivan Puntos 151

Por si a alguien le interesa, lo he resuelto utilizando el algoritmo de Nelder-Mead en su lugar. El rendimiento podría ser mejor, pero no quería perder más tiempo en ello.

Esta es la solución final:

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));

        }
    }
}

Finanhelp.com

FinanHelp es una comunidad para personas con conocimientos de economía y finanzas, o quiere aprender. Puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X