private static MarketObservable GetCcyPair(NumeraireSimulator numeraireSimulator, Currency ccy) { // TODO: Currency pair should be passed in somehow rather than constructed here so that there is no risk of names not coinciding. MarketObservable index = new CurrencyPair($"{ccy}{numeraireSimulator.GetNumeraireCurrency()}", ccy, numeraireSimulator.GetNumeraireCurrency()); return(index); }
/// <summary> /// The main constructor for the Coordinator. /// </summary> /// <param name="numeraire">A special simulator that also includes the numeraire. There is only one of these.</param> /// <param name="simulators">Optionally any extra simulators independent of the first. Can be an empty list.</param> public Coordinator(NumeraireSimulator numeraire, List <Simulator> simulators, int N) { this.numeraire = numeraire; this.simulators = simulators; this.simulators.Insert(0, numeraire); this.N = N; valueCurrency = numeraire.GetNumeraireCurrency(); }
/// <summary> /// Creates a lookup so that the coordinator knows which simulator provides each required index. /// </summary> /// <exception cref="System.ArgumentException"> /// Cannot use 'ANY' as the valuation currency when the portfolio includes cashflows in multiple currencies. /// </exception> /// <exception cref="System.IndexOutOfRangeException"> /// Required index: " + index.ToString() + " is not provided by any of the simulators. /// or /// Required currency pair: " + index.ToString() + " is not provided by any of the simulators /// </exception> private static Dictionary <MarketObservable, Simulator> AssociateFactorsWithSimulators( IEnumerable <IProduct> portfolio, NumeraireSimulator numeraireSimulator, List <Simulator> availableSimulators) { // Find which simulator will provide each of the potentially required MarketObservables. var mappedSimulators = new Dictionary <MarketObservable, Simulator>(); var indices = new HashSet <MarketObservable>(); foreach (var product in portfolio) { foreach (var index in product.GetRequiredIndices()) { indices.Add(index); } foreach (var ccy in product.GetCashflowCurrencies().Where(c => c != numeraireSimulator.GetNumeraireCurrency())) { indices.Add(GetCcyPair(numeraireSimulator, ccy)); } } foreach (var index in indices) { if (mappedSimulators.ContainsKey(index)) { continue; } var found = false; foreach (var sim in availableSimulators) { if (!sim.ProvidesIndex(index)) { continue; } if (!found) { mappedSimulators[index] = sim; found = true; } else { throw new ArgumentException(index + " is provided by more than one simulator."); } } if (found) { continue; } throw new IndexOutOfRangeException("Required index: " + index + " is not provided by any of the simulators."); } return(mappedSimulators); }
/// <summary> /// Initializes the simulators by telling them at which dates they will need to provide which market indices. /// </summary> /// <param name="extraDates">Extra dates over and above the contract dates where the simulators will need to /// provide their indices.</param> private void InitializeSimulators(List <Product> portfolio, List <Date> extraDates) { // Reset all the simulators foreach (Simulator simulator in simulators) { simulator.Reset(); } // Set up the simulators for the times at which they will be queried foreach (Product product in portfolio) { product.SetValueDate(valueDate); // Tell the simulators at what times indices will be required. foreach (MarketObservable index in product.GetRequiredIndices()) { List <Date> requiredTimes = product.GetRequiredIndexDates(index); simulators[indexSources[index]].SetRequiredDates(index, requiredTimes); simulators[indexSources[index]].SetRequiredDates(index, extraDates); } // Tell the nummeraire simulator at what times it will be required. // Tell the FX simulators at what times they will be required. foreach (Currency ccy in product.GetCashflowCurrencies()) { List <Date> requiredDates = product.GetCashflowDates(ccy); numeraire.SetNumeraireDates(requiredDates); numeraire.SetNumeraireDates(extraDates); if (ccy != numeraire.GetNumeraireCurrency()) { MarketObservable index = new CurrencyPair(ccy, numeraire.GetNumeraireCurrency()); simulators[indexSources[index]].SetRequiredDates(index, requiredDates); simulators[indexSources[index]].SetRequiredDates(index, extraDates); } } } // Prepare all the simulators foreach (Simulator simulator in simulators) { simulator.Prepare(); } }
/// <summary> /// Initializes the simulators by telling them at which dates they will need to provide which market indices. /// </summary> /// <param name="valueDate"></param> /// <param name="portfolio"></param> /// <param name="fwdDates">Extra dates over and above the contract dates where the simulators will need to /// provide their indices. This is likely to be forward values required in EPE and PFE profiles.</param> /// <param name="numeraireSimulator"></param> /// <param name="mappedSimulators"></param> /// <param name="availableSimulators"></param> private static void PrepareSimulators(Date valueDate, List <IProduct> portfolio, List <Date> fwdDates, NumeraireSimulator numeraireSimulator, Dictionary <MarketObservable, Simulator> mappedSimulators, List <Simulator> availableSimulators) { // Reset all the simulators foreach (var simulator in availableSimulators) { simulator.Reset(); } // Set up the simulators for the times at which they will be queried foreach (var product in portfolio) { product.SetValueDate(valueDate); // Tell the simulators at what times indices will be required. foreach (var index in product.GetRequiredIndices()) { var requiredTimes = product.GetRequiredIndexDates(index); mappedSimulators[index].SetRequiredDates(index, requiredTimes); mappedSimulators[index].SetRequiredDates(index, fwdDates); } // Tell the numeraire simulator at what times it will be required. // Tell the FX simulators at what times they will be required. foreach (var ccy in product.GetCashflowCurrencies()) { var requiredDates = product.GetCashflowDates(ccy); numeraireSimulator.SetNumeraireDates(requiredDates); numeraireSimulator.SetNumeraireDates(fwdDates); if (ccy != numeraireSimulator.GetNumeraireCurrency()) { var ccyPair = GetCcyPair(numeraireSimulator, ccy); mappedSimulators[ccyPair].SetRequiredDates(ccyPair, requiredDates); mappedSimulators[ccyPair].SetRequiredDates(ccyPair, fwdDates); } } foreach (var simulator in availableSimulators) { simulator.Prepare(valueDate); } numeraireSimulator.Prepare(valueDate); } // Prepare all the simulators foreach (var simulator in availableSimulators) { simulator.Prepare(valueDate); } }
/// <summary> /// Performs the simulation chunk that updates /// the cashflows per product and per path. /// the /// </summary> /// <param name="portfolio"></param> /// <param name="allDates">The dates at which the underlying factors will be saved for later regression.</param> /// <param name="simulatedCFs">The cashflows converted to the value currency and deflated with the numeraire. Updated /// by this function.</param> /// <param name="simulatedRegs">The values of the regressors by path and date.</param> /// <param name="pathStart">The path start.</param> /// <param name="pathEnd">The path end.</param> private void PerformSimulationChunk(List <IProduct> portfolio, List <Date> allDates, SimulatedCashflows simulatedCFs, SimulatedRegressors simulatedRegs, int pathStart, int pathEnd) { // clone the simulators and portfolio if this is running multi threaded var localPortfolio = portfolio.Clone(); var(localNumeraire, localSimulators) = GetCopyOfSimulators(); var mappedSimulators = AssociateFactorsWithSimulators(localPortfolio, localNumeraire, localSimulators); PrepareSimulators(_valueDate, localPortfolio, allDates, localNumeraire, mappedSimulators, localSimulators); foreach (var product in localPortfolio) { product.SetValueDate(_valueDate); } for (var pathCounter = pathStart; pathCounter < pathEnd; pathCounter++) { var numeraireAtValue = localNumeraire.Numeraire(_valueDate); // Run the simulation foreach (var simulator in localSimulators) { simulator.RunSimulation(pathCounter); } // get the underlying factors for (var fwdDateCounter = 0; fwdDateCounter < allDates.Count; fwdDateCounter++) { var independentCounter = 0; foreach (var simulator in localSimulators) { var underlyingFactors = simulator.GetUnderlyingFactors(allDates[fwdDateCounter]); foreach (var factor in underlyingFactors) { simulatedRegs.Add(pathCounter, fwdDateCounter, independentCounter, factor); independentCounter++; } } } // use the simulators that now contain a simulation to provide market observables to the // products. for (var productCounter = 0; productCounter < localPortfolio.Count; productCounter++) { var product = localPortfolio[productCounter]; product.Reset(); foreach (var index in product.GetRequiredIndices()) { var simulator = mappedSimulators[index]; var requiredDates = product.GetRequiredIndexDates(index); var indices = simulator.GetIndices(index, requiredDates); product.SetIndexValues(index, indices); } var timesAndCfs = product.GetCFs(); foreach (var cf in timesAndCfs) { if (cf.Currency.Equals(_numeraireSimulator.GetNumeraireCurrency())) { var cfValue = cf.Amount * numeraireAtValue / localNumeraire.Numeraire(cf.Date); simulatedCFs.Add(productCounter, pathCounter, new Cashflow(cf.Date, cfValue, cf.Currency)); } else { var currencyPair = GetCcyPair(localNumeraire, cf.Currency); var simulator = mappedSimulators[currencyPair]; var fxRate = simulator.GetIndices(currencyPair, new List <Date> { cf.Date })[0]; var cfValue = fxRate * cf.Amount * numeraireAtValue / localNumeraire.Numeraire(cf.Date); simulatedCFs.Add(productCounter, pathCounter, new Cashflow(cf.Date, cfValue, cf.Currency)); } } } } }
/// <summary> /// Performs the simulation chunk that updates /// the cashflows per product and per path. /// the /// </summary> /// <param name="portfolio"></param> /// <param name="fwdValueDates">The dates at which the underlying factors will be saved for later regression.</param> /// <param name="simulatedCFs">The cashflows converted to the value currency and deflated witht he numeaire. Updated /// by this function.</param> /// <param name="simulatedRegs">The valuesor the regressors by path and date.</param> /// <param name="pathStart">The path start.</param> /// <param name="pathEnd">The path end.</param> private void PerformSimulationChunk(List <Product> portfolio, List <Date> fwdValueDates, SimulatedCashflows simulatedCFs, SimulatedRegressors simulatedRegs, int pathStart, int pathEnd) { // clone the simulators and portfolio if this is running multi threaded List <Product> localPortfolio; NumeraireSimulator localNumeraire = null; List <Simulator> localSimulators = null; if (useThreads) { localPortfolio = portfolio.Clone(); CopySimulators(out localNumeraire, out localSimulators); } else { localPortfolio = portfolio; localNumeraire = numeraire; localSimulators = simulators; } for (int pathCounter = pathStart; pathCounter < pathEnd; pathCounter++) { double numeraireAtValue = localNumeraire.Numeraire(valueDate); // Run the simulation foreach (Simulator simulator in localSimulators) { simulator.RunSimulation(pathCounter); } // get the underlying factors for (int fwdDateCounter = 0; fwdDateCounter < fwdValueDates.Count; fwdDateCounter++) { int independentCounter = 0; foreach (Simulator simulator in localSimulators) { double[] underlyingFactors = simulator.GetUnderlyingFactors(fwdValueDates[fwdDateCounter]); for (int thisIndependentCounter = 0; thisIndependentCounter < underlyingFactors.Length; thisIndependentCounter++) { simulatedRegs.Add(pathCounter, fwdDateCounter, independentCounter, underlyingFactors[thisIndependentCounter]); independentCounter++; } } } // use the simulators that now contain a simulation to provide market observables to the // products. for (int productCounter = 0; productCounter < localPortfolio.Count; productCounter++) { Product product = localPortfolio[productCounter]; product.Reset(); foreach (MarketObservable index in product.GetRequiredIndices()) { Simulator simulator = localSimulators[indexSources[index]]; List <Date> requiredDates = product.GetRequiredIndexDates(index); double[] indices = simulator.GetIndices(index, requiredDates); product.SetIndexValues(index, indices); } List <Cashflow> timesAndCFS = product.GetCFs(); foreach (Cashflow cf in timesAndCFS) { if (cf.currency.Equals(valueCurrency)) { double cfValue = cf.amount * numeraireAtValue / localNumeraire.Numeraire(cf.date); simulatedCFs.Add(productCounter, pathCounter, new Cashflow(cf.date, cfValue, cf.currency)); } else { MarketObservable currencyPair = new CurrencyPair(cf.currency, localNumeraire.GetNumeraireCurrency()); Simulator simulator = localSimulators[indexSources[currencyPair]]; double fxRate = simulator.GetIndices(currencyPair, new List <Date> { cf.date })[0]; double cfValue = fxRate * cf.amount * numeraireAtValue / localNumeraire.Numeraire(cf.date); simulatedCFs.Add(productCounter, pathCounter, new Cashflow(cf.date, cfValue, cf.currency)); } } } } }