public static ConstructGen<double> DoScaleWeights(ConstructGen<double> wts_, TraderArgs args_, Func<DateTime,double> getVolTargetForDate_) { if (wts_.ColumnHeadings == null) wts_.ColumnHeadings = args_.Products.Select(x => x.Name).ToArray(); var logReturns = args_.AllProductPrices(fillInGapsWithPrevious_: true).ToLogReturns( args_.Products.Select(x => x.Convention).ToArray()); var scaledWts = new ConstructGen<double>(wts_.ColumnHeadings); foreach (var date in wts_.Dates) { var wtArr = wts_.GetValues(date); for (int i = 0; i < wtArr.Length; ++i) if (double.IsInfinity(wtArr[i])) wtArr[i] = 0d; int indexOfDate = logReturns.FindIndexOfEffectiveDateOnDate(date); indexOfDate = (indexOfDate < 252) ? 252 : indexOfDate - 1; // note offset var subValues = logReturns.GetSubValues(logReturns.Dates[indexOfDate - 251], logReturns.Dates[indexOfDate]); var covArr = SI.Data.FXHistCovar.MatCovar(subValues.ToArray()); var cov = new CovarianceItem(covArr); scaledWts.SetValues(date, cov.ScaleSeries(wtArr, getVolTargetForDate_(date))); } return scaledWts; }
protected override ReturnsEval.DataSeriesEvaluator doPnl(TraderArgs args_, ConstructGen<double> wts_) { var priceReturns = args_.AllProductPrices(fillInGapsWithPrevious_: true) .ToReturns(args_.Products.Select(x => x.Convention).ToArray()); var stratReturns = new ConstructGen<double>(priceReturns.ColumnHeadings); double[] appliedWeights = null; for (int i = 0; i < priceReturns.Dates.Count; ++i) { var date = priceReturns.Dates[i]; var priceReturnsArr = priceReturns.GetValues(date); if (appliedWeights != null) { for (int j = 0; j < priceReturnsArr.Length; ++j) stratReturns.SetValue(date, j, appliedWeights[j]*priceReturnsArr[j]); } if (wts_.Dates.Contains(date)) { appliedWeights = wts_.GetValues(date); } } var eval = new ReturnsEval.DataSeriesEvaluator("Gen pnl from weights", ReturnsEval.DataSeriesType.Returns); eval.AddInnerSeries(stratReturns.Dates.ToArray(), stratReturns.ToArray(), stratReturns.ColumnHeadings); return eval; }
public override double[] GetContToVar(double[] wts_, DateTime date_, TraderArgs args_) { CovarianceItem covar = null; DateTime d = date_; covar = Singleton<CovarianceSource>.Instance.GetCovarianceForDateElesePrevious(d); double[] expWeights = new double[covar.ComponentIds.Count]; int[] indices = new int[wts_.Length]; for (int i = 0; i < args_.Products.Count; ++i) { indices[i] = covar.ComponentIds.IndexOf(((ProductFX)args_.Products[i]).CoreProduct.ID); expWeights[indices[i]]=wts_[i]; } double [] contToVar = covar.GetContToVar(expWeights,args_.ScaleUsingDiagMatrix); // reshape into length of input products... double[] ret = new double[wts_.Length]; for (int i = 0; i < wts_.Length; ++i) ret[i] = contToVar[indices[i]]; return ret; }
protected override SI.ReturnsEval.DataSeriesEvaluator doPnl(TraderArgs args_, ConstructGen<double> wts_) { ConstructGen<double> allCcys = new ConstructGen<double>(Singleton<FXIDs>.Instance.ColumnHeadings); for (int i = 0; i < args_.Products.Count; ++i) { ProductFX prod = (ProductFX)args_.Products[i]; allCcys.SetColumnValues(prod.CoreProduct.ArrayIndex, wts_.Dates.ToArray(), wts_.GetColumnValues(i)); } var result = ReturnsFromFXWeights.DoIt_DailyWeights(allCcys); var eval = new ReturnsEval.DataSeriesEvaluator("FX pnl", ReturnsEval.DataSeriesType.Returns); if (args_.WtIndicators.Any()) eval.Name = string.Format("FX : {0}", args_.WtIndicators[0].ToString()); eval.AddInnerSeries(result.CombinedPnl.Dates.ToArray(), result.CombinedPnl.ToArray(), result.CombinedPnl.ColumnHeadings); return eval; }
public static ConstructGen<double> DoScaleWeights(ConstructGen<double> weights_, double targetVol_, TraderArgs args_) { //Singleton<Data.FXHistCovar>.Instance.Ensure(weights_.Dates.ToArray(),63); ConstructGen<double> ret = new ConstructGen<double>(weights_.ArrayLength); ret.ColumnHeadings = weights_.ColumnHeadings; foreach (DateTime date in weights_.Dates) { DateTime d = date; CovarianceItem covar = null; switch (args_.VolTypeForScaling) { case VolType.covar: covar = Singleton<SI.Data.CovarianceSource>.Instance.GetCovarianceForDateElesePrevious(d); //if (covar == null) //{ // DateTime prevTradingDate = MyCalendar.PrevTradeDate(date, "LNB"); // covar = Singleton<Data.FXHistCovar>.Instance[prevTradingDate, 252]; //} break; //case Technicals.VolType.hist: // covar = Singleton<Data.FXHistCovar>.Instance[d, args_.HistCovWindowLength]; // break; default: throw new Exception("voltype not implemented"); } // extract and scale weights double[] weighted = weightFX(weights_.GetValues(date), covar, args_, targetVol_); ret.SetValues(date, weighted); } return ret; }
private void generateRawResults(TraderArgs args_) { m_resultsWts.Clear(); m_resultsFilter.Clear(); foreach (ProductBase product in args_.Products) { if (args_.WtIndicators.Count > 0) { var list = new List<DatedDataCollectionGen<double>>(); foreach (IndicatorBase indic in args_.WtIndicators) { list.Add(indic.GenerateWeightSeries(product, args_.WtsMinDate)); } m_resultsWts[product] = list; } // now not trending signals... if (args_.FilterIndicators.Count > 0) { var list = new List<DatedDataCollectionGen<double>>(); foreach (IndicatorBase indic in args_.FilterIndicators) { list.Add(indic.GenerateWeightSeries(product,args_.WtsMinDate)); } m_resultsFilter[product] = list; } } m_trendExistResult.Clear(); if (args_.TrendExistenceIndic != null) { foreach (ProductBase product in args_.Products) { m_trendExistResult[product] = args_.TrendExistenceIndic.GenerateWeightSeries(product,args_.WtsMinDate); } } }
public static double[] weightFX(double[] input_, CovarianceItem covar_, TraderArgs args_,double targetVol_) { double[] scaleThis = new double[covar_.ComponentIds.Count]; int[] indices = new int[input_.Length]; for (int i = 0; i < args_.Products.Count; ++i) { indices[i] = covar_.ComponentIds.IndexOf(((ProductFX)args_.Products[i]).CoreProduct.ID); scaleThis[indices[i]] = input_[i]; } double[] scaled = covar_.ScaleSeries(scaleThis, targetVol_,args_.ScaleUsingDiagMatrix); // contrains weights? if (args_.WtConstraints != null && args_.WtConstraints.Enabled) { bool cont = true; int iterationCount = 0; double tolerance = 0.05; // 5% tolerance on constraint int iterationMax = 100; while (cont && iterationCount < iterationMax) { cont = false; double upperLimit = args_.WtConstraints.UpperConstraint + Math.Abs(args_.WtConstraints.UpperConstraint * tolerance); double lowerLimit = args_.WtConstraints.LowerConstraint - Math.Abs(args_.WtConstraints.LowerConstraint * tolerance); for (int i = 0; i < scaled.Length; ++i) { if (scaled[i] < lowerLimit) { scaled[i] = args_.WtConstraints.LowerConstraint; } if (scaled[i] > upperLimit) { scaled[i] = args_.WtConstraints.UpperConstraint; } } if (args_.WtConstraints.ReScale) { scaled = covar_.ScaleSeries(scaled, targetVol_); cont = true; } ++iterationCount; } } // reshape into length of input products... double[] ret = new double[input_.Length]; for (int i = 0; i < input_.Length; ++i) ret[i] = scaled[indices[i]]; return ret; }
public ReturnsEval.DataSeriesEvaluator Trade(TraderArgs args_) { var c = GetWeights(args_); return doPnl(args_, c); }
private DateTime findStartDate(TraderArgs args_) { DateTime ret = DateTime.MaxValue; if (args_.WtsMinDate >= DateTime.Today) return args_.WtsMinDate; foreach (ProductBase product in m_resultsWts.Keys) { foreach (DatedDataCollectionGen<double> dd in m_resultsWts[product]) if (dd!=null && dd.Length>0 && dd.Dates[0] < ret) ret = dd.Dates[0]; if(m_resultsFilter.Count>0) foreach (DatedDataCollectionGen<double> dd in m_resultsFilter[product]) if (dd.Dates[0] > ret) ret = dd.Dates[0]; } if (args_.RebalFrequency == RebalFreq.Weekly || args_.RebalFrequency == RebalFreq.BiWeekly) while (ret.DayOfWeek != args_.DayOfWeek) ret = ret.AddDays(1.0); if (args_.RebalFrequency == RebalFreq.Monthly) while (ret.Day != args_.MonthlyDayStart) ret = ret.AddDays(1.0); while (ret.DayOfWeek == DayOfWeek.Saturday || ret.DayOfWeek == DayOfWeek.Sunday) ret = ret.AddDays(1.0); if (args_.RebalFrequency == RebalFreq.ParticularDate) ret = args_.ParticularDate; // while (ret.Day != 4 || ret.DayOfWeek==DayOfWeek.Saturday || ret.DayOfWeek==DayOfWeek.Sunday ) // ret = ret.AddDays(1.0); return ret; }
public static List<DateTime> GetRebalDates(TraderArgs args_, DateTime startDate) { if (args_.RebalDates != null) return args_.RebalDates; List<DateTime> ret = GenerateRebalDates(args_.RebalFrequency, startDate); args_.RebalDates = ret; return ret; }
public static void processToTrigger(ConstructGen<double> wts_, TraderArgs args_, Trader trader_) { if (wts_.Dates.Count == 0) return; if (args_.TriggerArgs == null) return; List<int> datesIndicesToRemove=new List<int>(); List<int> varContTopIndices = new List<int>(); List<int> topWtPos = new List<int>(); double[] before = wts_.GetValues(wts_.Dates[0]); double[] varContBefore = (args_.TriggerArgs.DoVarFlipsTrigger) ? trader_.GetContToVar(before, wts_.Dates[0], args_) : null; if (args_.TriggerArgs.DoVarFlipsTrigger) getTopVarIndicies(varContTopIndices, varContBefore, args_.TriggerArgs.VarFlipsTrigger.ConsiderTopVarNumber); if (args_.TriggerArgs.DoTopInSizeTrigger) getTopPosSizeIndicies(topWtPos, before, args_.TriggerArgs.TopInSizeTrigger.ConsiderTopInSizeNumber); List<DateTime> removeTheseDates = new List<DateTime>(); int daysSinceRebal = 0; List<DateTime> includeTheseDates = new List<DateTime>(); if (args_.TriggerArgs.AlwayRebalFrequencyEnabled) { // get the dates of rebal the rebalfrequency implies includeTheseDates = GenerateRebalDates(args_.TriggerArgs.AlwaysRebalFrequency, wts_.Dates[0]); } for (int i = 1; i < wts_.Dates.Count; ++i) { double[] wtsToday = wts_.GetValues(wts_.Dates[i]); bool remove=true; ++daysSinceRebal; // have we exceeded the maximum number of specified days without a rebal? if (remove && args_.TriggerArgs.MaxDaysWithoutRebalEnabled && args_.TriggerArgs.MaxDaysWithoutRebal <= daysSinceRebal) { remove = false; } // do we want to always rebal on a particular day of the week if (remove && args_.TriggerArgs.AlwaysRebalOnDayOfWeekEnabled && args_.TriggerArgs.AlwayRebalOnThisDayOfWeek == wts_.Dates[i].DayOfWeek) { remove = false; } // is the date in the list of dates that we always want to maintain if (remove && includeTheseDates.Contains(wts_.Dates[i])) { remove = false; } // positions that have changed signs must be greater than NUM_CHANGE_FREQ in order for the day to be kept if (remove && (args_.TriggerArgs.ChangeSignEnabled || args_.TriggerArgs.ChangeSignOnProportionEnabled)) { int countChanged = 0; for (int j = 0; j < wts_.ArrayLength; ++j) { // change sign in position means keep if (Statistics.AreSameSign(before[j], wtsToday[j]) == false) ++countChanged; } int changeOnThisNumber = int.MaxValue; // if have decided to change on number of positions that have changed sign... if (args_.TriggerArgs.ChangeSignEnabled) changeOnThisNumber = Math.Min(changeOnThisNumber, args_.TriggerArgs.MinNumberOfItemsToChange); // if have decided to change on proportion of tradeable products to change sign if (args_.TriggerArgs.ChangeSignOnProportionEnabled) { int validCount = numValidProductsOnDate(wts_.Dates[i], args_); int numProp = Convert.ToInt32(Convert.ToDouble(validCount) * args_.TriggerArgs.ChangeSignOnThisProportion); changeOnThisNumber = Math.Min(changeOnThisNumber, numProp); } if (countChanged >= changeOnThisNumber) remove = false; } // proportion of portfolio turnover if (remove && args_.TriggerArgs.TurnoverEnabled) { double sumOfTurnover = 0.0; double sumOfPositions = 0.0; for (int j = 0; j < wts_.ArrayLength; ++j) { sumOfTurnover += Math.Abs(wtsToday[j] - (before[j])); sumOfPositions += Math.Abs(before[j]); } double propChanged = sumOfTurnover / sumOfPositions; if (propChanged >= args_.TriggerArgs.TurnoverThreshold/* TAG:MA32DaysMin && daysSinceRebal>1*/) remove = false; } // trade the flipped positions but don't re-scale everything else if (remove==false && args_.TriggerArgs.DontTopLevelScaleIntraWeek == true && args_.TriggerArgs.AlwaysRebalOnDayOfWeekEnabled && args_.TriggerArgs.AlwayRebalOnThisDayOfWeek != wts_.Dates[i].DayOfWeek) { double[] newArray = new double[before.Length]; for (int j = 0; j < wts_.ArrayLength; ++j) { if (Statistics.AreSameSign(before[j], wtsToday[j])) newArray[j] = before[j]; else newArray[j] = wtsToday[j]; } wts_.SetValues(wts_.Dates[i], newArray); wtsToday = newArray; } // var flips if (remove && args_.TriggerArgs.DoVarFlipsTrigger) { int numFlipped = 0; foreach (int index in varContTopIndices) if (Statistics.AreSameSign(before[index], wtsToday[index]) == false) ++numFlipped; if (numFlipped >= args_.TriggerArgs.VarFlipsTrigger.NumFlipsTrigger) remove = false; } // top in size flips if (remove && args_.TriggerArgs.DoTopInSizeTrigger) { int numFlipped = 0; foreach (int index in topWtPos) if (Statistics.AreSameSign(before[index], wtsToday[index]) == false) ++numFlipped; if (numFlipped >= args_.TriggerArgs.TopInSizeTrigger.NumFlipsTrigger) remove = false; } if (remove) { removeTheseDates.Add(wts_.Dates[i]); ++daysSinceRebal; } else { before = wtsToday; //varContBefore = (trader_ == null || args_.TriggerArgs.VarFlipsTrigger == null || args_.TriggerArgs.VarFlipsTrigger.Enabled == false) ? null : trader_.GetContToVar(before, wts_.Dates[i], args_); daysSinceRebal = 0; if (args_.TriggerArgs.DoVarFlipsTrigger) { varContBefore = trader_.GetContToVar(before, wts_.Dates[i], args_); getTopVarIndicies(varContTopIndices, varContBefore, args_.TriggerArgs.VarFlipsTrigger.ConsiderTopVarNumber); } if (args_.TriggerArgs.DoTopInSizeTrigger) getTopPosSizeIndicies(topWtPos, before, args_.TriggerArgs.TopInSizeTrigger.ConsiderTopInSizeNumber); } } foreach (DateTime date in removeTheseDates) wts_.RemoveValues(date); }
public static ConstructGen<double> DoScaleWeights(ConstructGen<double> wts_, double targetVol_, TraderArgs args_) { return DoScaleWeights(wts_, args_, x => targetVol_); }
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); }
protected abstract ReturnsEval.DataSeriesEvaluator doPnl(TraderArgs args_, ConstructGen<double> wts_);
public ReturnsEval.DataSeriesEvaluator DoPnl(TraderArgs args_) { ConstructGen<double> wts = GetWeights(args_); return DoPnl(args_, wts); }
public ReturnsEval.DataSeriesEvaluator DoPnl(TraderArgs args_, ConstructGen<double> wts_) { return doPnl(args_, wts_); }
public abstract double[] GetContToVar(double[] wts_, DateTime date_, TraderArgs args_);
public abstract ConstructGen<double> ScaleWeights(ConstructGen<double> weights_, double targetVol_, TraderArgs args_);
private static int numValidProductsOnDate(DateTime date_, TraderArgs args_) { int count = 0; foreach (ProductBase pb in args_.Products) if (pb.IsValid(date_)) ++count; return count; }
public static ConstructGen<double> getFilters(TraderArgs args_, List<DateTime> rebalDates_, IDictionary<ProductBase,List<DatedDataCollectionGen<double>>> resultsFilter_) { ConstructGen<double> ret = new ConstructGen<double>(args_.Products.Count); if (resultsFilter_==null || resultsFilter_.Count == 0) { ret.InitialiseToValue(rebalDates_, 1d); } else { for (int j = 0; j < args_.Products.Count; ++j) { DatedDataCollectionGen<double> dataForProductAndFilter = resultsFilter_[args_.Products[j]][0]; foreach (DateTime date in rebalDates_) { ret.SetValue( date, j, dataForProductAndFilter.ValueOnDate(date, args_.DayOffset)); } } } // use this opportunity to count out those products that are not valid on this date for (int j = 0; j < args_.Products.Count; ++j) { foreach (DateTime date in rebalDates_) { if (args_.Products[j].IsValid(date) == false) ret.SetValue(date, j, double.NaN); } } // ConstructDisplay.Show(ret, args_.Products.ToArray(), "Filter series"); return ret; }
public override double[] GetContToVar(double[] wts_, DateTime date_, TraderArgs args_) { throw new NotImplementedException(); }
public override ConstructGen<double> ScaleWeights(ConstructGen<double> weights_, double targetVol_, TraderArgs args_) { return DoScaleWeights(weights_, targetVol_, args_); }
public static void processToTrigger(ConstructGen<double> wts_, TraderArgs args_) { processToTrigger(wts_, args_, null); }
private ConstructGen<double>[] getWeights(TraderArgs args_, List<DateTime> rebalDates_, ConstructGen<double> filter_) { if (m_resultsWts.Count == 0) return null; ConstructGen<double>[] allWts = new ConstructGen<double>[args_.WtIndicators.Count]; // go through all wtIndicators - will normally only be one for (int i = 0; i < args_.WtIndicators.Count; ++i) { ConstructGen<double> all_c,rebal_c; int length = args_.Products.Count; all_c = new ConstructGen<double>(length); rebal_c = new ConstructGen<double>(length); for (int j = 0; j < args_.Products.Count; ++j) { // extract the signal series for this wtIndicator and product DatedDataCollectionGen<double> dataForProductAndIndicator = m_resultsWts[args_.Products[j]][i]; // put the data in the contruct that represents the signal at every point for (int y = 0; y < dataForProductAndIndicator.Length; ++y) all_c.SetValue( dataForProductAndIndicator.Dates[y], j, dataForProductAndIndicator.Data[y]); // put the data in the construct that represents the signal just on rebal days // NOTE: is offset by 1 day so not in sample foreach (DateTime d in rebalDates_) { //if (d == new DateTime(2010, 3, 19)) // System.Diagnostics.Debugger.Break(); if (args_.Products[j].IsValid(d)) rebal_c.SetValue(d, j, dataForProductAndIndicator.ValueOnDate(d, args_.DayOffset)); } } // c is now a representation of the signal for all products on all days // do we want the product of the weights to determine which products can have positions on different days? if (args_.UseWeightsForFilter) { foreach (DateTime d in rebalDates_) { for (int ii = 0; ii < rebal_c.ArrayLength; ++ii) if (double.IsNaN(rebal_c.GetValue(d, ii))) filter_.SetValue(d, ii, double.NaN); } } // multiply it by the filter to get rid of non-eligible days rebal_c = multiply(rebal_c, filter_,false); //ConstructDisplay.Show(rebal_c, args_.Products.ToArray(), "raw signal * filter"); // now need to scale the weights based on the weighting scheme supplied on the signal indicator // create a construct which will be the multiple foreach (SI.Research.Backtest.Builder.Model.WtScheme transform in args_.WtIndicators[i].TransformList) { ConstructGen<double> wts = new ConstructGen<double>(length); wts.InitialiseToValue(rebalDates_,1d); transform.DoWeights(rebal_c, all_c, wts, args_.Products,filter_); wts = multiply(wts, filter_, true); rebal_c = wts; //ConstructDisplay.Show(rebal_c, args_.Products.ToArray(), "weights"); } //ConstructDisplay.Show(rebal_c, new object[] { "wts" }, "transformed weights"); allWts[i] = rebal_c; } return allWts; }
public ConstructGen<double> GetWeights(TraderArgs args_) { generateRawResults(args_); // generate all indicators List<DateTime> rebalDates = getRebalDates(args_); // save them so we can use them later args_.RebalDates = rebalDates; // get the filter construct first ConstructGen<double> filter = getFilters(args_, rebalDates, m_resultsFilter); //ConstructDisplay.Show(filter, args_.Products.ToArray(), "Filter Values"); // get the wts ConstructGen<double>[] wts = getWeights(args_, rebalDates, filter); if (wts.Length > 0 && args_.CombineWeightArgs != null) { // do we want to scale each signal before combining? if (args_.CombineWeightArgs.ScaleBeforeCombine) for (int i = 0; i < wts.Length; ++i) wts[i] = ScaleWeights(wts[i], args_.ScaleToThisVol, args_); // do we want to scale the allocation to each signal? if (args_.CombineWeightArgs.ScaleWeightSignalsEnabled) { double currAlloc = args_.CombineWeightArgs.StratWeightStartAlloc; for (int i = 0; i < wts.Length; ++i) { wts[i] = wts[i].MultiplyBy(currAlloc); currAlloc += args_.CombineWeightArgs.StratWeightAllocIncrement; } } } // combine the different signals ConstructGen<double> c = wts[0]; if (args_.CombineWeightArgs != null && args_.CombineWeightArgs.CombineMethod == StratCombineMethod.MULT) { c = wts[0]; for (int i = 1; i < wts.Length; ++i) c = multiply(c, wts[i], false); } else if (args_.CombineWeightArgs != null && args_.CombineWeightArgs.CombineMethod == StratCombineMethod.AGREE) { c = wts[0]; for (int i = 1; i < wts.Length; ++i) c = agreeSign(c, wts[i]); } else if (args_.CombineWeightArgs != null && args_.CombineWeightArgs.CombineMethod == StratCombineMethod.ADD) { c = wts[0]; for (int i = 1; i < wts.Length; ++i) c = c.Plus(wts[i]); } else if (args_.CombineWeightArgs != null && args_.CombineWeightArgs.CombineMethod == StratCombineMethod.LIST) { System.Diagnostics.Debug.Assert(args_.CombineWeightArgs.AllocList != null, "Combine method has been set to 'LIST' but no allocation list has been set"); System.Diagnostics.Debug.Assert(args_.CombineWeightArgs.AllocList.ArrayLength == wts.Length, "Set of weights to combine doesn't match arraylength of ConstructGen<double> that has been set to express the allocations."); // get a list of common dates List<DateTime> commondates = new List<DateTime>(); foreach (DateTime date in wts[0].Dates) { for (int i = 1; i < wts.Length; ++i) if (wts[i].Dates.Contains(date) == false) continue; commondates.Add(date); } ConstructGen<double> comb = new ConstructGen<double>(wts[0].ArrayLength); for (int i = 0; i < wts.Length; ++i) { foreach (DateTime date in commondates) { if(comb.Dates.Contains(date)==false) comb.SetValues(date,new double[comb.ArrayLength]); double alloc = args_.CombineWeightArgs.AllocList.GetValue(date, i); for (int j = 0; j < comb.ArrayLength; ++j) comb.AddValue(date, j, alloc * wts[i].GetValue(date, j)); } } c = comb; } else if (args_.CombineWeightArgs == null && wts.Length > 1) throw new Exception("Don't know how to combine the signals into one."); else if (args_.CombineWeightArgs != null) throw new Exception("Strategy combine method not implemented"); // scale to the target vol if (args_.ScaleToVol) c = ScaleWeights(c, args_.ScaleToThisVol, args_); // if we want to if (args_.RebalFrequency == RebalFreq.Trigger) processToTrigger(c, args_, this); //ConstructDisplay.Show(c, args_.Products.ToArray(), "final wts"); c.ColumnHeadings = args_.Products.Select<ProductBase, string>(x => x.ToString()).ToArray<string>(); return c; }
private List<DateTime> getRebalDates(TraderArgs args_) { if (args_.RebalDates != null) return args_.RebalDates; return GetRebalDates(args_, findStartDate(args_)); }
public static KeyValuePair<TraderArgs, ConstructGen<double>> GetBackTestWeights(CarryOptARgs args_) { TraderArgs args = new TraderArgs(); Array.ForEach(Singleton<FXIDs>.Instance.ToArray(), x => args.Products.Add(ProductFX.GetCached(x))); args.RebalFrequency = args_.Freq; args.DayOfWeek = DayOfWeek.Tuesday; args.ParticularDate = args_.ParticularRebalDate; var dates = args_.Freq == RebalFreq.ParticularDate ? Trader.GenerateRebalDates(args.RebalFrequency, args.ParticularDate) : Trader.GetRebalDates(args, MyCalendar.NextDayOfWeek(SI.Data.DataConstants.DATA_START, DayOfWeek.Tuesday)); var carryCon = Singleton<FXCarry>.Instance.GetData( startDate_: MyCalendar.PrevWeekDay(dates[0].AddDays(-2d*args_.DaysToAverageCarryNDF)), endDate_: DateTime.Today); var tranCosts = Singleton<FXTransactionCosts>.Instance.GetData(MyCalendar.PrevWeekDay(dates[0].AddDays(-10d)), DateTime.Today, false); var dxyScores = Singleton<DXYScore_21>.Instance.Scores; DatedDataCollectionGen<double> outScores = null; double outthreshold = 0d; switch (args_.OutMethod) { case CarryOptARgs.CarryOutMethod.ATMVolsPercentileAbove50: outScores = Singleton<ATMVolsRank>.Instance.ATM_1W_o1Y; outthreshold = 0.5; break; case CarryOptARgs.CarryOutMethod.MOVEIndexPercentilAbove50: outScores = Singleton<MOVEScore_21>.Instance.Pxs.ToPercentileRanked(252); outthreshold = 0.5; break; default: outScores = null; outthreshold = 0d; break; } int numCcys = args.Products.Count; var 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 = 1d; double usdMax = 1d; /* target vol */ double targetVol = args_.TargetVol; foreach (DateTime date in dates) { if (args_.StartDate != null && date <= args_.StartDate.Value) continue; var simCov = getCovarianceItem(date, args_.SimCov, args_.HistCovarWindowLength); var scaleCov = (args_.ScaleCov == args_.SimCov) ? simCov : getCovarianceItem(date, args_.ScaleCov, args_.HistCovarWindowLength); /* covariance */ double[,] cov = simCov.Data; /* carry */ double[] carry = new double[numCcys]; { // need to take 5 day average starting on the day before the date we're rebalancing int endIndex = carryCon.Dates.Contains(date) ? carryCon.Dates.IndexOf(date) - 1 : carryCon.Dates.Count - 1; for (int i = 0; i < carryCon.ArrayLength; ++i) { // currency isn't valid = carry stays at zero if (Singleton<FXIDs>.Instance[i].IsValid(date) == false) continue; var cryLength = Singleton<FXIDs>.Instance[i].IsGroup(FXGroup.NDF) ? args_.DaysToAverageCarryNDF : args_.DaysToAverageCarry; double sum = 0d; for (int j = 0; j < cryLength; ++j) sum += carryCon.GetValue(carryCon.Dates[endIndex - j], i); carry[i] = sum / Convert.ToDouble(cryLength); Logger.Debug( string.Format("Carry of {0} over {1} = {2}", Singleton<FXIDs>.Instance[i], cryLength, carry[i]), typeof (Carry)); } } /* tcosts */ double[] tcosts = new double[numCcys]; { if (args_.IncludeTranCosts) { 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 (args_.PrevWeights != null) prevWts = args_.PrevWeights; 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; mins[i] = !args_.ShouldIncludeCurrency(date,ccy) ? 0d : -args_.GetWeightConstraint(ccy); maxs[i] = !args_.ShouldIncludeCurrency(date, ccy) ? 0d : args_.GetWeightConstraint(ccy); } } switch (args_.USDConstraints) { case CarryOptARgs.DXYConstraint.Dynamic: { /* USD min max */ double score = (args_.DXYScore != 0d) ? args_.DXYScore : dxyScores.ValueOnDate(date, -1); if (score > 1d) { usdMin = 1d; usdMax = 5d; } else if (score < -1d) { usdMin = -5d; usdMax = 1d; } else { usdMin = 1d; usdMax = 1d; } } break; case CarryOptARgs.DXYConstraint.Flat: { usdMin = 1d; usdMax = 1d; } break; case CarryOptARgs.DXYConstraint.None: { usdMin = -5d; usdMax = 5d; } break; } var result = Singleton<ExcelOptimizer>.Instance.DoIt( numCcys, targetVol, cov, carry, tcosts, prevWts, mins, maxs, usdMin, usdMax, optHorizon, date); double[] optWts = result.Wts; if (args_.ScaleCov != args_.SimCov) optWts = scaleCov.ScaleSeries(optWts, targetVol); if (outScores != null && outScores.ValueOnDate(date) > outthreshold) optWts = new double[optWts.Length]; wts.SetValues(date, optWts); } Singleton<ExcelOptimizer>.Instance.Dispose(); return new KeyValuePair<TraderArgs, ConstructGen<double>>(args, wts); }