Example #1
0
    public static RVOlOptResult GetBackTestWeights(RVolOptArgs optArgs_)
    {
      TraderArgs args = new TraderArgs();

      Array.ForEach(Singleton<FXIDs>.Instance.ToArray(), x => args.Products.Add(ProductFX.GetCached(x)));

      args.RebalFrequency = optArgs_.Freq;
      args.DayOfWeek = DayOfWeek.Tuesday;
      args.ParticularDate = optArgs_.ParticularRebalDate;

      bool doNeg = false;

      List<DateTime> dates;
      if (optArgs_.Freq == RebalFreq.ParticularDate)
        dates = Trader.GenerateRebalDates(args.RebalFrequency, args.ParticularDate);
      else
        dates = Trader.GetRebalDates(args, MyCalendar.NextDayOfWeek(SI.Data.DataConstants.DATA_START, DayOfWeek.Tuesday));

      //ConstructGen<double> carryCon = Singleton<FXCarry>.Instance.GetAnnualizedCarry(MyCalendar.PrevWeekDay(dates[0].AddDays(-10d)), DateTime.Today, 5, false);
      var tranCosts = Singleton<FXTransactionCosts>.Instance.GetData(MyCalendar.PrevWeekDay(dates[0].AddDays(-10d)), DateTime.Today, false);
      var dxyScores = Singleton<DXYScore_21>.Instance.Scores;
      var vixScores = Singleton<VIXScore_21>.Instance.Scores;

      IList<string> exclude = new List<string>();
      {
        if (optArgs_.CcysToExclude != null)
          foreach (string s in optArgs_.CcysToExclude.ToUpper().Trim().Split(','))
            exclude.Add(s);
      }

      // set up scores
      switch (optArgs_.SwitchExpReturn)
      {
        case SwitchSignType.None:
          doNeg = false;
          break;
        case SwitchSignType.AlwaysNegative:
          doNeg = true;
          break;
        case SwitchSignType.DXY21:
          dxyScores = Singleton<DXYScore_21>.Instance.Scores;
          break;
        //case SwitchSignType.CustomDXY21:
        //  dxyScores = Singleton<QC.Common.CurrencyUniverseScore_21>.Instance.Scores;
        //  break;
        //case SwitchSignType.DXY_EMEA21:
        //  dxyScores = Singleton<QC.Common.CurrencyEMScore_21>.Instance.Scores;
        //  break;
        //case SwitchSignType.DXY_LATAM21:
        //  dxyScores = Singleton<QC.Common.CurrencyLATAMScore_21>.Instance.Scores;
        //  break;
        //case SwitchSignType.DXY_NJA21:
        //  dxyScores = Singleton<QC.Common.CurrencyNJAScore_21>.Instance.Scores;
        //  break;
        //case SwitchSignType.DXY_G1021:
        //  dxyScores = Singleton<QC.Common.CurrencyG10Score_21>.Instance.Scores;
        //  break;
        //case SwitchSignType.COTMonWts:
        //  {
        //    ConstructGen<double> cotWts = Backtests.getWE(Strat.COT1Mon).Key;
        //    dxyScores = cotWts.SumRows();
        //    dxyScores = dxyScores.MultiplyBy(-1d);
        //  }
        //  break;
        default:
          throw new Exception(string.Format("Need to code options for {0}", optArgs_.SwitchExpReturn.ToString()));
      }


      Logger.Info(string.Format("Switching threshold on scores is {0}", optArgs_.SwitchThreshold.ToString()), typeof(RVOLOpt));

      List<DateTime> triggerDates = new List<DateTime>();

      // do we want to look for trigger every day?
      if (optArgs_.SwitchDailyTrigger && !double.IsNaN(optArgs_.SwitchThreshold))
      {
        for (int i = 1 + Math.Abs(optArgs_.SwitchDayOffset); i < dxyScores.Length; ++i)
        {
          if (dates[0] > dxyScores.Dates[i]) continue;

          if (dxyScores.Dates[i].Month == 12 && (dxyScores.Dates[i].Day == 25 || dxyScores.Dates[i].Day == 26))
            continue;

          double dxyToday = dxyScores.Data[i + optArgs_.SwitchDayOffset];
          double dxyYest = dxyScores.Data[i + optArgs_.SwitchDayOffset - 1];

          if (dxyToday >= optArgs_.SwitchThreshold && dxyYest < optArgs_.SwitchThreshold)
          {
            if (dates.Contains(dxyScores.Dates[i]) == false)
            {
              dates.Add(dxyScores.Dates[i]);
              triggerDates.Add(dxyScores.Dates[i]);
            }
          }
          else if (dxyToday < optArgs_.SwitchThreshold && dxyYest >= optArgs_.SwitchThreshold)
          {
            if (dates.Contains(dxyScores.Dates[i]) == false)
            {
              dates.Add(dxyScores.Dates[i]);
              triggerDates.Add(dxyScores.Dates[i]);
            }
          }
        }
        QuickSort.Sort<DateTime>(dates);
      }
      //else if (optArgs_.SwitchExpReturn == SwitchSignType.COTMonWts)
      //{
      //  ConstructGen<double> cotWts = Backtests.getWE(Strat.COT1Mon).Key;
      //  dxyScores = cotWts.SumRows();
      //  dxyScores = dxyScores.MultiplyBy(-1d);
      //}

      int numCcys = Singleton<FXIDs>.Instance.Count;
      ConstructGen<double> wts = new ConstructGen<double>(Singleton<FXIDs>.Instance.ColumnHeadings);

      /* lincon */
      double[,] lincon = new double[6, numCcys + 1];

      /* minlincon & maxlincon */
      double[,] minlincon = new double[6, 1];
      double[,] maxlincon = new double[6, 1];
      {
        minlincon[0, 0] = 0d; minlincon[1, 0] = -10d; minlincon[2, 0] = 0d; minlincon[3, 0] = -10d; minlincon[4, 0] = 0d; minlincon[5, 0] = -10d;
        maxlincon[0, 0] = 10d; maxlincon[1, 0] = 0d; maxlincon[2, 0] = 10d; maxlincon[3, 0] = 0d; maxlincon[4, 0] = 10d; maxlincon[5, 0] = 0d;
      }

      /* opt horizon */
      string optHorizon = "2W";

      /* USD constraints */
      double usdMin = -5d;
      double usdMax = 5d;

      usdMax = Math.Abs(optArgs_.USDAbsLimit);
      usdMin = 1d - Math.Abs(optArgs_.USDAbsLimit - 1d);

      /* target vol */
      double targetVol = 0.012159;

      /* equal expected return */
      double[] eerPos = new double[numCcys];
      for (int i = 0; i < eerPos.Length; ++i) eerPos[i] = optArgs_.ReturnMagnitude == 0d ? 0.1 : Math.Abs(optArgs_.ReturnMagnitude);
      double[] eerNeg = new double[numCcys];
      for (int i = 0; i < eerNeg.Length; ++i) eerNeg[i] = optArgs_.ReturnMagnitude == 0d ? -0.1 : -Math.Abs(optArgs_.ReturnMagnitude);

      foreach (DateTime date in dates)
      {
        if (optArgs_.StartDate != null && date <= optArgs_.StartDate.Value)
          continue;

        Logger.Debug(string.Format("Generatig weights for {0}", date.ToString("dd-MMM-yyy")), typeof (RVOLOpt));

        /* covariance */

        CovarianceItem simCov = (optArgs_.SimCov == VolType.covar)
          ? Singleton<CovarianceSource>.Instance.GetCovarianceForDateElesePrevious(date)
          : Singleton<FXHistCovar>.Instance.FindForDate(date, optArgs_.HistCovarWindowLength);
        CovarianceItem scaleCov = (optArgs_.ScaleCov == VolType.covar)
          ? Singleton<CovarianceSource>.Instance.GetCovarianceForDateElesePrevious(date)
          : Singleton<FXHistCovar>.Instance.FindForDate(date, optArgs_.HistCovarWindowLength);



        /* tcosts */
        double[] tcosts = new double[numCcys];
        {
          if (optArgs_.IncludeTransactionsCosts)
          {
            int endIndex = tranCosts.Dates.Contains(date) ? tranCosts.Dates.IndexOf(date) - 1 : tranCosts.Dates.Count - 1;
            tcosts = tranCosts.GetValues(tranCosts.Dates[endIndex]);
          }
        }

        /* oldWts */
        double[] prevWts = new double[numCcys];
        {
          if (optArgs_.PrevWts != null)
            prevWts = optArgs_.PrevWts;
          else if (wts.Dates.Count > 0)
            prevWts = wts.GetValues(wts.Dates[wts.Dates.Count - 1]);
        }

        /* mins & maxs */
        double[] mins = new double[numCcys];
        double[] maxs = new double[numCcys];
        {
          for (int i = 0; i < numCcys; ++i)
          {
            Currency ccy = Singleton<FXIDs>.Instance[i];

            // must be zero for non-elegible currencies
            if (ccy.IsValid(date) == false) continue;

            // exclude this currency
            if (exclude.Contains(ccy.Code)) continue;

            //mins[i] = exclude.Contains(ccy.Code) ? 0d : !ccy.IsGroup(FXGroup.G10) ? -0.121591 : -0.3039775;
            //maxs[i] = exclude.Contains(ccy.Code) ? 0d : !ccy.IsGroup(FXGroup.G10) ? 0.121591 : 0.3039775;

            switch (optArgs_.WeightsSplitType)
            {
              case WtsSplitType.G10_EM:
                {
                  maxs[i] = ccy.IsGroup(FXGroup.G10) ? Math.Abs(optArgs_.G10MaxWeight) : Math.Abs(optArgs_.EMMaxWeight);
                }
                break;
              case WtsSplitType.G10_NDF_NonNDFEM:
                {
                  if (ccy.IsGroup(FXGroup.G10))
                    maxs[i] = Math.Abs(optArgs_.G10MaxWeight);
                  else if (ccy.IsGroup(FXGroup.NDF))
                    maxs[i] = Math.Abs(optArgs_.NDFMaxWeight);
                  else
                    maxs[i] = Math.Abs(optArgs_.NonNDFEMMaxWeight);
                }
                break;
              case WtsSplitType.Custom:
                {
                  maxs[i] = Math.Abs(optArgs_.CustomMaxMins[i]);
                }
                break;
            }

            mins[i] = -maxs[i];
          }
        }

        /* neg expected return or not */
        if (double.IsNaN(optArgs_.SwitchThreshold) == false)  // ... if we're looking for a threshold
        {
          double score = dxyScores.ValueOnDate(date, optArgs_.SwitchDayOffset);
          if (score > optArgs_.SwitchThreshold)
            doNeg = true;
          else
            doNeg = false;
        }

        /* go */
        //IMOptPortfolio(targetVol, cov, carry, tcosts, prevWts, mins, maxs, lincon, minlincon, maxlincon, optHorizon, lastArg);

        switch (optArgs_.ExpectedReturnType)
        {
          case ExpectedReturnType.Equal:
            // do nothing - is default option
            break;
          case ExpectedReturnType.OneOverVol:
          {
            double[] vols = simCov.IndividualVols;
            for (int i = 0; i < eerPos.Length; ++i)
            {
              eerPos[i] = 1d/vols[i];
              eerNeg[i] = -1d/vols[i];
            }
          }
            break;
          case ExpectedReturnType.EqualExceptLowestCorrel_1:
          case ExpectedReturnType.EqualExceptLowestCorrel_2:
          {
            var rankThreshold = 0d;

            switch (optArgs_.ExpectedReturnType)
            {
              case ExpectedReturnType.EqualExceptLowestCorrel_1:
                rankThreshold = 1.1d;
                break;
              case ExpectedReturnType.EqualExceptLowestCorrel_2:
                rankThreshold = 2.1d;
                break;
            }

            var corrRanks =
              Singleton<CovarianceSource>.Instance.GetCovarianceForDateElesePrevious(date, 5)
                .GetIndividualAverageCorrelations()
                .ToRanks(ascending_: true);

            for (int i = 0; i < eerPos.Length; ++i)
            {
              var rank = corrRanks[i];
              eerNeg[i] = (rank <= rankThreshold) ? 0.1 : -0.1;
              eerPos[i] = (rank <= rankThreshold) ? -0.1 : 0.1;
            }
          }
            break;
          case ExpectedReturnType.EqualExceptLowestCorrel_pct10:
          {
            var pctThreshold = 0.1d;

            var indivAvgCorrelations = Singleton<CovarianceSource>.Instance.GetCovarianceForDateElesePrevious(date, 5)
              .GetIndividualAverageCorrelations();

            double min = indivAvgCorrelations.Min();
            double max = indivAvgCorrelations.Max();

            double threshold = min + ((max - min)*pctThreshold);

            for (int i = 0; i < eerPos.Length; ++i)
            {
              eerNeg[i] = (indivAvgCorrelations[i] <= threshold) ? 0.1 : -0.1;
              eerPos[i] = (indivAvgCorrelations[i] <= threshold) ? -0.1 : 0.1;
            }
          }
            break;
        }

        if (optArgs_.OptType == OptimationType.Excel)
        {

          var result = Singleton<ExcelOptimizer>.Instance.DoIt(
            numCcys, targetVol, simCov.Data, doNeg ? eerNeg : eerPos, tcosts, prevWts, mins, maxs, usdMin, usdMax, optHorizon,
            date);

          //if (result.OptimizationResult != Optimizer.CarryOptResult.OptResult.OK_SolutionFoundAllConstraintsSatisfied)
          //  System.Diagnostics.Debugger.Break();

          double[] dateWts = result.Wts;

          if (result.Wts.SumAbs() == 0d)
            System.Diagnostics.Debugger.Break();

          // cross-sectional demean?
          if (optArgs_.CSDemean)
          {
            double sum = 0d;
            double count = 0d;
            for (int i = 0; i < dateWts.Length; ++i)
              if (dateWts[i] != 0d)
              {
                sum += dateWts[i];
                count += 1d;
              }
            double avg = sum/count;
            for (int i = 0; i < dateWts.Length; ++i)
              if (dateWts[i] != 0d)
                dateWts[i] -= avg;

            dateWts = scaleCov.ScaleSeries(dateWts, CovarianceItem.VolFromVaR(0.02));
          }

          wts.SetValues(date, dateWts);
        }
        else if (optArgs_.OptType == OptimationType.SolverFoundation)
        {
          var model = new RvolSolveModel(
            simCov,
            Singleton<FXIDs>.Instance.Select(
              (x, i) => new CurrencyLine(x, doNeg ? eerNeg[i] : eerPos[i], mins[i], maxs[i])).ToArray(),
            targetVol)
          {
            SumOfWeightsMin=0d,
            SumOfWeightsMax=0d
          };

          new RvolSolver().Solve(model);

          wts.SetValues(date, model.CurrencyLines.Select(x => x.Weight).ToArray());
        }
      }

      if(optArgs_.OptType==OptimationType.Excel)
        Singleton<ExcelOptimizer>.Instance.Dispose();

      return new RVOlOptResult()
      {
        TArgs = args,
        Weights = wts,
        TriggerDates = triggerDates
      };
      //return new KeyValuePair<TraderArgs, Construct>(args, wts);
    }
Example #2
0
    public static void Test()
    {

      var model = new RvolSolveModel(
        targetVol_: 0.0121519,
        cov_: Singleton<SI.Data.CovarianceSource>.Instance.GetCovariance(DateTime.Today.AddDays(-1d)),
        ccys_: Singleton<SI.Data.FXIDs>.Instance.Select(x => new CurrencyLine(
          ccy_: x,
          expectedReturn_: 0.1,
          minWt_: x.IsGroup(Data.FXGroup.G10) ? -0.31 : -0.1215914,
          maxWeight_: x.IsGroup(Data.FXGroup.G10) ? 0.31 : 0.1215914)).ToArray()
        )
      {
        SumOfWeightsMin = 0d,
        SumOfWeightsMax = 1d,
      };

      new RvolSolver().SolveQuadratic(model);

      Console.WriteLine("ben");

      return;

      var result = Singleton<ExcelOptimizer>.Instance.DoIt(
        model.CurrencyLines.Length,
        model.TargetVol,
        model.Covar.Data,
        model.CurrencyLines.Select(x => x.ExpectedReturn).ToArray(),
        ExtensionMethods.CreateArrayRep<double>(0d, model.CurrencyLines.Length),
        ExtensionMethods.CreateArrayRep<double>(0d, model.CurrencyLines.Length),
        model.CurrencyLines.Select(x => x.MinWeight).ToArray(),
        model.CurrencyLines.Select(x => x.MaxWeight).ToArray(),
        1d,
        1d,
        "2W",
        DateTime.Today);

      Singleton<ExcelOptimizer>.Instance.Dispose();

      var list = new System.ComponentModel.BindingList<CompareResult>();

      for (int i = 0; i < model.CurrencyLines.Length; ++i)
      {
        list.Add(
          new CompareResult()
          {
            Currency = model.CurrencyLines[i].Ccy.Code,
            SolverFoundation = model.CurrencyLines[i].Weight,
            XLL = result.Wts[i]
          });
      }

      list.DisplayInGrid("result comparison");
    }
Example #3
0
    public void Solve(RvolSolveModel model_)
    {
      var context = SolverContext.GetContext();

      context.ClearModel();

      var ccyModel = context.CreateModel();

      buildCovariants(model_.Covar);

      {
        // create an integer set with ccys
        Set ccys = new Set(Domain.Integer, "ccys");

        //
        // parameters
        //

        Parameter minwt = new Parameter(Domain.Real, "minwt", ccys);
        minwt.SetBinding<CurrencyLine>(model_.CurrencyLines, "MinWeight", "Id");

        Parameter maxwt = new Parameter(Domain.Real, "maxwt", ccys);
        maxwt.SetBinding<CurrencyLine>(model_.CurrencyLines, "MaxWeight", "Id");

        Parameter expreturn = new Parameter(Domain.Real, "expreturn", ccys);
        expreturn.SetBinding<CurrencyLine>(model_.CurrencyLines, "ExpectedReturn", "Id");

        Parameter tvol = new Parameter(Domain.Real, "tvol");
        tvol.SetBinding(Math.Pow(0.01215914, 2d));

        Parameter pCovariants = new Parameter(Domain.Real, "Covariants", ccys, ccys);
        pCovariants.SetBinding(Covariants, "Variance", "CcyI", "CcyJ");

        ccyModel.AddParameters(minwt, maxwt, expreturn, tvol, pCovariants);

        //
        // decisions
        //

        Decision allocations = new Decision(Domain.Real, "wt", ccys);
        allocations.SetBinding(model_.CurrencyLines, "Weight", "Id");

        ccyModel.AddDecisions(allocations);

        //
        // constraints
        //

        // weight limits

        ccyModel.AddConstraint("wtbounds", Model.ForEach(ccys, s => minwt[s] <= allocations[s] <= maxwt[s]));

        // sum of weights constraint

        if (model_.SumOfWeightsMin.HasValue && model_.SumOfWeightsMax.HasValue && Math.Abs(model_.SumOfWeightsMin.Value - model_.SumOfWeightsMax.Value) < 0.000001)
        {
          ccyModel.AddConstraint("usdcontraint", Model.Equal(model_.SumOfWeightsMin.Value, Model.Sum(Model.ForEach(ccys, x => allocations[x]))));
        }
        else
        {
          if (model_.SumOfWeightsMin.HasValue)
            ccyModel.AddConstraint("usdconstraintMin",
              Model.LessEqual(model_.SumOfWeightsMin, Model.Sum(Model.ForEach(ccys, s => allocations[s]))));

          if (model_.SumOfWeightsMax.HasValue)
            ccyModel.AddConstraint("usdconstraintMax",
              Model.GreaterEqual(model_.SumOfWeightsMax, Model.Sum(Model.ForEach(ccys, s => allocations[s]))));
        }

        // targetting a specific volatility

        ccyModel.AddConstraint("variance",
          Model.GreaterEqual(tvol,
              //Model.Sqrt
              (
                Model.Sum
                  (
                    Model.ForEach
                      (
                        ccys, CcyI =>
                          Model.ForEach
                            (
                              ccys, CcyJ =>
                                Model.Product(pCovariants[CcyI, CcyJ], allocations[CcyI], allocations[CcyJ])
                            )
                      )
                  )
              )
            )
          );


        // goal

        ccyModel.AddGoal("maxexpreturn", GoalKind.Maximize,
          Model.Sum(Model.ForEach(ccys, s => expreturn[s]*allocations[s])));

      }

      var soluation = context.Solve();
      context.PropagateDecisions();
      MessageBox.Show(soluation.GetReport().ToString());
      //MessageBox.Show(string.Format("Target Vol: {0}", model_.CurrentTargettedVol.ToString("##0.0#%")));
      //MessageBox.Show(string.Format("Sum of weights: {0}",model_.CurrencyLines.Select(x=>x.Weight).Sum()));
    }
Example #4
0
    public void SolveQuadratic(RvolSolveModel model_)
    {
      int m = model_.CurrencyLines.Length;
      //int iterations = 1;

      //for (int reqIx = 0; reqIx < iterations; ++reqIx)
      {
        InteriorPointSolver solver = new InteriorPointSolver();
        int[] allocations = new int[m];

        for (int invest = 0; invest < m; ++invest)
        {
          string name = model_.CurrencyLines[invest].Ccy.Code;

          solver.AddVariable(name, out allocations[invest]);
          solver.SetBounds(allocations[invest], 
            model_.CurrencyLines[invest].MinWeight,
            model_.CurrencyLines[invest].MaxWeight);
        }

        int expectedReturn;
        solver.AddRow("expectedReturn", out expectedReturn);
        //int sumZero;
        //solver.AddRow("sumZero", out sumZero);

        for (int invest = 0; invest < m; ++invest)
        {
          solver.SetCoefficient(expectedReturn, allocations[invest], model_.CurrencyLines[invest].ExpectedReturn);
          //solver.SetCoefficient(sumZero, allocations[invest], 0);
        }

        int variance;
        solver.AddRow("variance", out variance);

        for (int invest = 0; invest < m; ++invest)
        {
          for (int jnvest = 0; jnvest < m; ++jnvest)
          {
            solver.SetCoefficient(variance, model_.Covar.Data[invest, jnvest], allocations[invest], allocations[jnvest]);
          }
        }

        var varianceTarget = Math.Pow(model_.TargetVol, 2d);

        solver.SetBounds(variance, double.NegativeInfinity, varianceTarget);

        // max expected return
        solver.AddGoal(expectedReturn, 1, false);

        InteriorPointSolverParams lpParams = new InteriorPointSolverParams();

        solver.Solve(lpParams);

        //if (solver.Result != LinearResult.Optimal)

        for (int invest = m; 0 <= --invest;)
        {
          model_.CurrencyLines[invest].Weight = (double) solver.GetValue(allocations[invest]);
        }
      }
    }