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); }
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"); }
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())); }
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]); } } }