/// <summary> /// This function requires that the end expiry point date is larger than the start expiry point date. /// It gets input of possible expiry months in integral numbers and output the true distance betweeen two expiry points and also the path. /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> /// <param name="expirySeries"></param> /// <param name="expiryPath"></param> /// <returns></returns> private static int TrueDistanceBetweenExpiryPoint(ExpiryPoint p1, ExpiryPoint p2, List <ExpiryPoint> expirySeries, out List <ExpiryPoint> expiryPath) { // The total true distance is the sum of the intervals between start point and end point. expiryPath = null; int trueDistance = 0; if (expirySeries == null || expirySeries.Count == 0) { return(trueDistance); } // This is the physical distance in units of month. int physicalDistance = (p2.Year.YearInNumber - p1.Year.YearInNumber) * 12 + (p2.Month.MonthInNumber - p1.Month.MonthInNumber); if (physicalDistance <= 0) { return(trueDistance); } // The output path contains true expiry path given whole expiry series and start/end points. expiryPath = new List <ExpiryPoint>(); for (int iDistance = 0; iDistance <= physicalDistance; iDistance++) { ExpiryPoint newPoint = ExpiryPoint.AddCreateExpiryPoint(p1, iDistance); if (ExpiryPoint.ContainDetermine(expirySeries, newPoint)) { expiryPath.Add(newPoint); trueDistance++; } } return(trueDistance - 1); }
/// <summary> /// This function will check whether the expiry point is contained in a list of expiry list with a more accurate way. /// </summary> /// <param name="expiryList"></param> /// <param name="expiry"></param> /// <returns></returns> public static bool ContainDetermine(List <ExpiryPoint> expiryList, ExpiryPoint expiry) { if (expiryList == null || expiryList.Count < 1) { return(false); } // We must loop through all the points in the list and compare the month part and the year part for each of them. foreach (ExpiryPoint eachPoint in expiryList) { if (eachPoint.Month.MonthInNumber == expiry.Month.MonthInNumber && eachPoint.Year.YearInNumber == expiry.Year.YearInNumber) { return(true); } } return(false); }
/// <summary> /// This function analyzes any possible position of expiry date for one product. /// </summary> /// <param name="existingFutureCollections"></param> /// <returns></returns> public static bool GetExpirySeriesForProduct(Dictionary <string, InstrumentName> existingFutureCollections, out List <ExpiryPoint> result) { result = null; ExpiryPoint expiryPoint = null; // Existing future contracts shows the existence of expiry series. foreach (InstrumentName instrumentName in existingFutureCollections.Values) { if (result == null) { result = new List <ExpiryPoint>(); } // We extract the expiry by the series name of the instrument, which contains the expiry date. if (TryExtractExpiryYearMonth(instrumentName.SeriesName, out expiryPoint) && !result.Contains(expiryPoint)) { result.Add(expiryPoint); } } return(result != null); }
/// <summary> /// This function uses the series name for each instrument name object and create an expiry point object. /// </summary> /// <param name="expirySeries"></param> /// <param name="expiryPoint"></param> /// <returns></returns> public static bool TryExtractExpiryYearMonth(string expirySeries, out ExpiryPoint expiryPoint) { expiryPoint = null; bool isSuccess = false; // The parsing object should contain MMMyy or yyyy/MM format only. DateTime dateTime; if (DateTime.TryParseExact(expirySeries, "MMMyy", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out dateTime)) { // Firstly, we consider whether it is in format of MMMyy because in most cases, it has date format of MMMyy. isSuccess = true; } else { if (DateTime.TryParseExact(expirySeries, "yyyy/MM", null, System.Globalization.DateTimeStyles.None, out dateTime)) { // Then we consider whether the date format is yyyy/MM. isSuccess = true; } else { // If both cases failed, we consider that we failed to parse the date time string. isSuccess = false; } } if (isSuccess) { // If successful, we create the expiry point required. int year = dateTime.Year; int month = dateTime.Month; expiryPoint = new ExpiryPoint(year - 2000, month); } return(isSuccess); }
}//listBoxProducts_SelectedIndexChanged() /// <summary> /// When the selected future instrument changes, it subscribes to the price for that instrument and also its spread components. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void listBoxInstruments_SelectedIndexChanged(object sender, EventArgs e) { // Wait the response from above and check which spread instruments are desired using boot-strapping method. string selectedInstrument = listBoxInstruments.SelectedItem.ToString(); InstrumentName selectedInstrumentName; // Found the spread components for the selected future instrument, which is normally in the long term. if (!m_FutureInstruments.TryGetValue(selectedInstrument, out selectedInstrumentName)) { Log.NewEntry(LogLevel.Warning, "Can not find selected instrument."); return; } // Firstly, subscribe to the price of that instrument. if (m_MarketTTAPI.RequestInstrumentSubscription(selectedInstrumentName)) { m_MarketReadTimer.Stop(); m_MarketReadTimer.Start(); Log.NewEntry(LogLevel.Minor, "Successfully send trade price subscription for instrument {0}.", selectedInstrumentName.FullName); } else { Log.NewEntry(LogLevel.Warning, "Failed to send trade price subscription for instrument {0}.", selectedInstrumentName.FullName); } // Then construct the spread in the path and subscribe to the prices for the spread instrument components. ExpiryPoint startPoint = new ExpiryPoint(14, 3); ExpiryPoint endPoint = null; if (!BootStrappingRule.TryExtractExpiryYearMonth(selectedInstrumentName.SeriesName, out endPoint)) { Log.NewEntry(LogLevel.Warning, "Failed to get the expiry point for future instrument {0}.", selectedInstrumentName); return; } else { Log.NewEntry(LogLevel.Minor, "Start bootstrapping algorithm for instrument {0}.", selectedInstrumentName); List <ExpiryPoint> expirySeries = null; List <List <ExpiryPoint> > spreadCombinations = null; // Expiry series only contains a limited number of expiry points. if (BootStrappingRule.GetExpirySeriesForProduct(m_FutureInstruments, out expirySeries)) { // Output the spread combinations by our algorithm under maximum step. if (BootStrappingRule.TryGetAllPathsByEnumeration(startPoint, endPoint, expirySeries, 5, out spreadCombinations)) { Log.BeginEntry(LogLevel.Minor, "Start bootstrapping enumeration:"); foreach (List <ExpiryPoint> row in spreadCombinations) { foreach (ExpiryPoint point in row) { Log.AppendEntry(point.ToString()); Log.AppendEntry(" "); } Log.AppendEntry("\r\n"); } Log.EndEntry(); Log.NewEntry(LogLevel.Minor, "Successfully completes enumeration algorithm."); } else { Log.NewEntry(LogLevel.Warning, "There is problem in getting path combinations"); return; } } else { Log.NewEntry(LogLevel.Warning, "There is problem in getting expiry series"); return; } // Try to load product spread information table and construct the spread names that we need. string productName = selectedInstrumentName.Product.ProductName; List <List <string> > spreadNameGeneratedCombinations = null; if (m_CSVSpreadInfoReader.TryDetectProductName(productName)) { string firstDelimiter; string secondDelimiter; m_CSVSpreadInfoReader.TryGetFirstDateDelimiter(productName, out firstDelimiter); m_CSVSpreadInfoReader.TryGetSecondDateDelimiter(productName, out secondDelimiter); // Use the spread info reader to construct the names for the spread instruments in all paths. if (!TryGenerateSpreadInstrumentNamesInAllPaths(firstDelimiter, secondDelimiter, spreadCombinations, out spreadNameGeneratedCombinations)) { Log.NewEntry(LogLevel.Warning, "Failed to generate spread names for all paths"); return; } else { // Output the spread names for all paths to log viewer. Log.BeginEntry(LogLevel.Minor); foreach (List <string> spreadNameEachPath in spreadNameGeneratedCombinations) { foreach (string spreadName in spreadNameEachPath) { Log.AppendEntry(spreadName); Log.AppendEntry(" "); } Log.AppendEntry("\r\n"); } Log.EndEntry(); Log.NewEntry(LogLevel.Minor, "Successfully generate spread names for all paths."); } } else { Log.NewEntry(LogLevel.Warning, "There is no entry for the product of {0} in the csv file", productName); return; } // Try to match the generated names with what we have downloaded from the TT. // Pull a valid path and subscribe to the prices for the spread components in that path. int startPathIndex = 0; if (!TryPullSpreadInstruments(startPathIndex, spreadNameGeneratedCombinations, out m_InstrumentSubscriptions)) { Log.NewEntry(LogLevel.Warning, "There is problem in pulling tt spread instruments"); return; } else { // This block subscribes to the inside market price for the spread instruments. foreach (InstrumentName instrumentName in m_InstrumentSubscriptions) { if (m_MarketTTAPI.RequestInstrumentSubscription(instrumentName)) { Log.NewEntry(LogLevel.Minor, "Successfully send trade price subscription for instrument {0}.", instrumentName.FullName); } else { Log.NewEntry(LogLevel.Warning, "Failed to send trade price subscription for instrument {0}.", instrumentName.FullName); } } } } }//listBoxInstruments_SelectedIndexChanged()
/// <summary> /// This function contains input of two expiry point, a list of expiry series containing expiry dates for the contract, and output all possible spread combinations. /// It uses a method of enumeration to calculate all the paths, making a list of any possible path if the starting point is fixed. /// It contains multiple steps to finish the paths from starting point to end point. Once a path ends at the end point, it constitutes a possible spread path. /// The program will add to the output list if the path ends, and continue to run other paths until they end. /// The expiry series contains a series number of expiry month that is possible. /// </summary> /// <param name="p1"></param> /// <param name="p2"></param> /// <param name="expirySeries"></param> /// <param name="spreadCombinations"></param> /// <returns></returns> public static bool TryGetAllPathsByEnumeration(ExpiryPoint p1, ExpiryPoint p2, List <ExpiryPoint> expirySeries, int maxStep, out List <List <ExpiryPoint> > spreadCombinations) { spreadCombinations = null; List <ExpiryPoint> expiryPath = null; // We see the true distance of expiry point as 1 unit. This can be one month or three months. // The total true distance is sum of intervals from the start date to the end date. int iTotalDistance = TrueDistanceBetweenExpiryPoint(p1, p2, expirySeries, out expiryPath); if (iTotalDistance > 0) { spreadCombinations = new List <List <ExpiryPoint> >(); List <List <int> > iPathCombination = new List <List <int> >(); List <List <int> > iTempCombination = new List <List <int> >(); List <List <int> > iPathResult = new List <List <int> >(); List <int> initialPath = new List <int>(); initialPath.Add(0); iPathCombination.Add(initialPath); int iStep = 0; // We do a truncate and only consider a spread combination path that contains limited steps. // This algorithm enumerates all the possible paths. If the path reaches the end point, add them to the final result list. while (iStep <= iTotalDistance && iStep < maxStep) { iTempCombination.Clear(); foreach (List <int> iPath in iPathCombination) { // Get the current path and enumerate all the possible step for the next move. int currentPos = iPath[iPath.Count - 1]; for (int iDistance = 1; iDistance <= iTotalDistance - currentPos; iDistance++) { List <int> uPath = new List <int>(); uPath.AddRange(iPath); uPath.Add(currentPos + iDistance); // If the next move reaches the end, add the path to the final result. if (iDistance == iTotalDistance - currentPos) { iPathResult.Add(uPath); continue; } iTempCombination.Add(uPath); } } iPathCombination = new List <List <int> >(iTempCombination); iStep++; } // Transform the integral path to expiry point path. foreach (List <int> iPath in iPathResult) { List <ExpiryPoint> path = new List <ExpiryPoint>(); foreach (int pos in iPath) { ExpiryPoint expiryPoint = expiryPath[pos]; path.Add(expiryPoint); } spreadCombinations.Add(path); } return(true); } else { return(false); } }
/// <summary> /// This function create a new expiry point given a current expiry point and month increment. /// </summary> /// <param name="p"></param> /// <param name="month"></param> /// <returns></returns> public static ExpiryPoint AddCreateExpiryPoint(ExpiryPoint p, int month) { ExpiryPoint np = new ExpiryPoint(p.Year.YearInNumber, p.Month.MonthInNumber + month); return(np); }