Пример #1
0
        private void PrepareStatData(IPortfolioBuilderBuildParams builderParams)
        {
            int nInstruments = builderParams.Instruments.Count;

            rets   = new double[nInstruments];
            stDevs = new double[nInstruments];
            matCov = new double[nInstruments, nInstruments];

            // getting instruments and calculating avg returns and stdevs for given time period
            IQuotesDalGetTimeSeriesValuesParams getQuotesParams = _quotesDal.CreateGetQuotesParams();

            getQuotesParams.PeriodStart = builderParams.PeriodStart;
            getQuotesParams.PeriodEnd   = builderParams.PeriodEnd;
            getQuotesParams.TimeFrame   = (QuotesInterfaces.ETimeFrame)builderParams.TimeFrame;
            getQuotesParams.Tickers.AddRange(builderParams.Instruments);

            IQuotesDalGetTimeseriesValuesResult getQuotesResult = _quotesDal.GetTimseriesValues(getQuotesParams);

            Dictionary <string, List <double> > returns = new Dictionary <string, List <double> >();

            // calculating returns & stdev
            for (int i = 0; i < nInstruments; ++i)
            {
                double avgRet = 0;
                returns.Add(getQuotesResult.Quotes[i].Ticker, new List <double>());
                for (int d = 0; d < getQuotesResult.Quotes[i].Quotes.Count(); ++d)
                {
                    double ret = (double)(getQuotesResult.Quotes[i].Quotes[d]["Close"] - getQuotesResult.Quotes[i].Quotes[d]["Open"]) / (double)getQuotesResult.Quotes[i].Quotes[d]["Open"];
                    returns[getQuotesResult.Quotes[i].Ticker].Add(ret);
                    avgRet += ret;
                }

                avgRet /= getQuotesResult.Quotes[i].Quotes.Count() - 1;
                switch (builderParams.TimeFrame)
                {
                case PortfolioInterfaces.ETimeFrame.Monthly:
                    avgRet = Math.Pow(1 + avgRet, 12) - 1;
                    break;
                }
                rets[i]   = avgRet;
                stDevs[i] = MathNet.Numerics.Statistics.Statistics.PopulationStandardDeviation(returns[getQuotesResult.Quotes[i].Ticker]);
                switch (builderParams.TimeFrame)
                {
                case PortfolioInterfaces.ETimeFrame.Monthly:
                    stDevs[i] *= Math.Sqrt(12);
                    break;
                }
            }

            // calculating covariances
            for (int k = 0; k < returns.Keys.Count; ++k)
            {
                for (int o = k; o < returns.Keys.Count; ++o)
                {
                    matCov[k, o] = MathNet.Numerics.Statistics.Statistics.PopulationCovariance(returns[returns.Keys.ElementAt(k)], returns[returns.Keys.ElementAt(o)]);
                    matCov[o, k] = matCov[k, o];
                }
            }
        }
        public void BuildPortfolio_5Tickers_MaxReturn_Success()
        {
            IQuotesDal dal = PrepareQuotesDal();

            IPortfolioBuilder builder = PreparePortfolioBuilder(dal);

            // preparing list of instruments
            IPortfolioBuilderBuildParams buildParams = builder.CreatePortfolioBuilderBuildParams();

            buildParams.Goal = EOptimizationGoal.Max; // maximizing portfolio return
            buildParams.OptimizationTarget = EProtfolioProperty.Return;
            buildParams.Instruments.Add(ConfigurationManager.AppSettings["TickerSPY"]);
            buildParams.Instruments.Add(ConfigurationManager.AppSettings["TickerQQQ"]);
            buildParams.Instruments.Add(ConfigurationManager.AppSettings["TickerGLD"]);
            buildParams.Instruments.Add(ConfigurationManager.AppSettings["TickerSLV"]);
            buildParams.Instruments.Add(ConfigurationManager.AppSettings["TickerTLT"]);

            buildParams.TimeFrame   = PortfolioInterfaces.ETimeFrame.Monthly;
            buildParams.PeriodStart = DateTime.Parse(ConfigurationManager.AppSettings["PeriodStart"]);
            buildParams.PeriodEnd   = DateTime.Parse(ConfigurationManager.AppSettings["PeriodEnd"]);

            // setting constraints
            foreach (var i in buildParams.Instruments)
            {
                IPortfolioBuilderConstraint cl = builder.CreateConstraint();
                cl.Operation = EConstraintOp.GreaterOrEqual;
                cl.Property  = EProtfolioProperty.Instrument;
                cl.Ticker    = i;
                cl.Value     = 0;

                IPortfolioBuilderConstraint cu = builder.CreateConstraint();
                cu.Operation = EConstraintOp.LessOrEqual;
                cu.Property  = EProtfolioProperty.Instrument;
                cu.Ticker    = i;
                cu.Value     = 1;

                buildParams.Constraints.Add(cl);
                buildParams.Constraints.Add(cu);
            }

            IPortfolioBuilderConstraint cstdev = builder.CreateConstraint();

            cstdev.Operation = EConstraintOp.LessOrEqual;
            cstdev.Property  = EProtfolioProperty.StDev;
            cstdev.Value     = (decimal)0.1; // limiting stdev to 10%

            buildParams.Constraints.Add(cstdev);

            IPortfolioBuilderBuildResult result = builder.Build(buildParams);

            Assert.IsTrue(result.Success);
            Assert.IsNotNull(result.Portfolio);
            Assert.IsNotNull(result.Portfolio.Instruments);
            Assert.AreEqual(result.Portfolio.Instruments.Count, 5);
            Assert.AreEqual(result.Portfolio.Instruments.Values.ElementAt(0) + result.Portfolio.Instruments.Values.ElementAt(1) + result.Portfolio.Instruments.Values.ElementAt(2) + result.Portfolio.Instruments.Values.ElementAt(3) + result.Portfolio.Instruments.Values.ElementAt(4), (decimal)1, "Sum of weights is not 100%");
        }
Пример #3
0
        public IPortfolioBuilderBuildResult Build(IPortfolioBuilderBuildParams buildParams)
        {
            IPortfolioBuilderBuildResult result = null;

            PrepareStatData(buildParams);

            fReturn = PrepareReturnFunction();
            fStDev  = PrepareStDevFunction();

            //lower bound is 0 - we cannot have negative weights
            double[] bndl = new double[buildParams.Instruments.Count];
            for (int i = 0; i < buildParams.Instruments.Count; ++i)
            {
                string symbol = buildParams.Instruments[i];
                IPortfolioBuilderConstraint constr = buildParams.Constraints.FirstOrDefault(x =>
                                                                                            x.Property == EProtfolioProperty.Instrument &&
                                                                                            x.Ticker == symbol &&
                                                                                            (x.Operation == EConstraintOp.Greater || x.Operation == EConstraintOp.GreaterOrEqual || x.Operation == EConstraintOp.Equal));
                bndl[i] = constr != null ? (constr.Value >= 0 ? (double)constr.Value : 0) : 0;
            }

            //upper bound
            double[] bndu = new double[buildParams.Instruments.Count];
            for (int i = 0; i < buildParams.Instruments.Count; ++i)
            {
                string symbol = buildParams.Instruments[i];
                IPortfolioBuilderConstraint constr = buildParams.Constraints.FirstOrDefault(x =>
                                                                                            x.Property == EProtfolioProperty.Instrument &&
                                                                                            x.Ticker == symbol &&
                                                                                            (x.Operation == EConstraintOp.Less || x.Operation == EConstraintOp.LessOrEqual || x.Operation == EConstraintOp.Equal));
                bndu[i] = constr != null ? (constr.Value >= 0 ? (double)constr.Value : 1) : 1;
            }

            // constraining weights' sum to 100%
            double[,] c = new double[1, buildParams.Instruments.Count + 1]; //{ 1, 1, 1, 1, 1, 1 }
            for (int i = 0; i < buildParams.Instruments.Count + 1; ++i)
            {
                c[0, i] = 1;
            }
            int[] ct = { 0 };

            // array to hold weights
            double[] w = new double[buildParams.Instruments.Count];

            alglib.minbleicstate  state;
            alglib.minbleicreport rep;

            double epsg   = 0.000001;
            double epsf   = 0;
            double epsx   = 0;
            int    maxits = 0;

            for (int i = 0; i < buildParams.MaxIterations; ++i)
            {
                GenerateRandomWeights(w);

                alglib.minbleiccreate(w, out state);
                alglib.minbleicsetbc(state, bndl, bndu);
                alglib.minbleicsetlc(state, c, ct);
                alglib.minbleicsetcond(state, epsg, epsf, epsx, maxits);

                switch (buildParams.OptimizationTarget)
                {
                case EProtfolioProperty.Return:
                    alglib.minbleicoptimize(state, FunReturn, null, null);
                    break;

                default:
                    throw new InvalidOperationException(string.Format("Optimization for {0} is not supported", buildParams.OptimizationTarget.ToString()));
                }

                alglib.minbleicresults(state, out w, out rep);
            }

            TPortfolio bestPortfolio = null;

            switch (buildParams.OptimizationTarget)
            {
            case EProtfolioProperty.Return:
                IPortfolioBuilderConstraint stDevConstr = buildParams.Constraints.FirstOrDefault(x => x.Property == EProtfolioProperty.StDev);

                IEnumerable <TPortfolio> orderedPortfolios = null;
                switch (buildParams.Goal)
                {
                case EOptimizationGoal.Max:
                    orderedPortfolios = portfolios.OrderByDescending(x => x.Return);
                    break;

                case EOptimizationGoal.Min:
                    orderedPortfolios = portfolios.OrderBy(x => x.Return);
                    break;
                }
                if (stDevConstr != null)
                {
                    switch (stDevConstr.Operation)
                    {
                    case EConstraintOp.Greater:
                        orderedPortfolios = orderedPortfolios.Where(x => x.StDev > (double)stDevConstr.Value);
                        break;

                    case EConstraintOp.Equal:
                        orderedPortfolios = orderedPortfolios.Where(x => Double.Equals(x.StDev, (double)stDevConstr.Value));
                        break;

                    case EConstraintOp.GreaterOrEqual:
                        orderedPortfolios = orderedPortfolios.Where(x => x.StDev >= (double)stDevConstr.Value);
                        break;

                    case EConstraintOp.Less:
                        orderedPortfolios = orderedPortfolios.Where(x => x.StDev < (double)stDevConstr.Value);
                        break;

                    case EConstraintOp.LessOrEqual:
                        orderedPortfolios = orderedPortfolios.Where(x => x.StDev <= (double)stDevConstr.Value);
                        break;
                    }
                }
                bestPortfolio = orderedPortfolios.FirstOrDefault();
                break;
            }

            // getting result

            result = new PortfolioBuilderBuildResult();
            if (bestPortfolio != null)
            {
                result.Success   = true;
                result.Portfolio = new Portfolio();
                for (int i = 0; i < bestPortfolio.Weights.Count; ++i)
                {
                    result.Portfolio.Instruments.Add(buildParams.Instruments[i], Math.Round((decimal)bestPortfolio.Weights[i], 4));
                }
                result.Return = (decimal)bestPortfolio.Return;
                result.StDev  = (decimal)bestPortfolio.StDev;
            }
            else
            {
                result.Success = false;
            }

            return(result);
        }