// // /// <summary> /// This function add hedge option to hedge option collection for the quote instrument. /// </summary> /// <param name="hedgeOption"></param> /// <returns></returns> public bool TryAddHedgeOption(HedgeOption hedgeOption) { bool isSuccess = false; if (!m_HedgeOptions.Contains(hedgeOption)) { m_HedgeOptions.Add(hedgeOption); m_PossibleHedgeCount++; isSuccess = true; } else { m_Log.NewEntry(LogLevel.Error, "Already added this hedge option for instrument {0}.", m_QuoteInstrument); return(isSuccess); } return(isSuccess); }
// ***************************************************************** // **** Properties **** // ***************************************************************** // // #endregion//Properties #region Public Methods // ***************************************************************** // **** Public Methods **** // ***************************************************************** // // // // // // /// <summary> /// This function will hedge options for the OMA trading strategy quote instrument. /// </summary> /// <param name="quoteInstrument"></param> /// <param name="hedgeOptionsString"></param> /// <returns></returns> public bool TryWriteHedgeOptionsForInstrument(InstrumentName quoteInstrument, out string hedgeOptionsString) { bool isSuccess = false; hedgeOptionsString = null; ProductTypes productTypes = quoteInstrument.Product.Type; string productName = quoteInstrument.Product.ProductName; string seriesName = quoteInstrument.SeriesName; List <HedgeOption> hedgeOptions = new List <HedgeOption>(); StringBuilder hedgeOptionsBuilder = new StringBuilder(); switch (productTypes) { case ProductTypes.Future: break; case ProductTypes.Spread: if (seriesName.Contains("Calendar")) { // Target: Calendar: 1xGE Sep14:-1xDec14 List <string> seriesNamesInTheString = new List <string>(); string pattern = @"[a-zA-Z]{3}[0-9]{2}"; MatchCollection matchCollection = Regex.Matches(seriesName, pattern); foreach (Match match in matchCollection) { if (match.Success) { seriesNamesInTheString.Add(match.Value); } } if (seriesNamesInTheString.Count == 2) { DateTime frontDateTime; DateTime endDateTime; if (!DateTime.TryParseExact(seriesNamesInTheString[0], "MMMyy", null, DateTimeStyles.None, out frontDateTime)) { m_Log.NewEntry(LogLevel.Error, "DateTime parsed failed for this string {0}.", seriesNamesInTheString[0]); return(isSuccess); } if (!DateTime.TryParseExact(seriesNamesInTheString[1], "MMMyy", null, DateTimeStyles.None, out endDateTime)) { m_Log.NewEntry(LogLevel.Error, "DateTime parsed failed for this string {0}.", seriesNamesInTheString[1]); return(isSuccess); } if (frontDateTime.Month % 3 != 0) { m_Log.NewEntry(LogLevel.Error, "Not need to write this hedge option because {0} month index is not multiples of 3.", seriesNamesInTheString[0]); return(isSuccess); } int duration = endDateTime.Month - frontDateTime.Month + (endDateTime.Year - frontDateTime.Year) * 12; if (duration % 3 != 0) { m_Log.NewEntry(LogLevel.Error, "Not need to write this hedge option because {0} duration is not multiples of 3.", seriesNamesInTheString[0]); return(isSuccess); } if (duration / 3 > 3) { m_Log.NewEntry(LogLevel.Error, "Not need to write this hedge option because {0} duration is too large than 3rd curve.", seriesNamesInTheString[0]); return(isSuccess); } int realDuration = duration / m_MonthCycleNumber; if (realDuration > 0) { List <DateTime> hedgeInstrumentStarts = new List <DateTime>(); List <DateTime> hedgeInstrumentEnds = new List <DateTime>(); List <int> quoteRatios = new List <int>(); List <int> hedgeRatios = new List <int>(); int caseNumber = 0; switch (realDuration) { case 1: // 5 cases in this situation. // 1: (1,2) to (2,3) 1:-1=1 hedgeInstrumentStarts.Add(frontDateTime.AddMonths(duration)); hedgeInstrumentEnds.Add(endDateTime.AddMonths(duration)); quoteRatios.Add(1); hedgeRatios.Add(-1); caseNumber++; // 2: (1,2) to (0,1) -1:1=1 hedgeInstrumentStarts.Add(frontDateTime.AddMonths(-duration)); hedgeInstrumentEnds.Add(endDateTime.AddMonths(-duration)); quoteRatios.Add(-1); hedgeRatios.Add(1); caseNumber++; // 3: (1,2) to (1,3) 2:-1=1 hedgeInstrumentStarts.Add(frontDateTime); hedgeInstrumentEnds.Add(endDateTime.AddMonths(duration)); quoteRatios.Add(2); hedgeRatios.Add(-1); caseNumber++; // 4: (1,2) to (0,2) -2:1=1 hedgeInstrumentStarts.Add(frontDateTime.AddMonths(-duration)); hedgeInstrumentEnds.Add(endDateTime); quoteRatios.Add(-2); hedgeRatios.Add(1); caseNumber++; // 5: (1,2) to (0,3) -3:1=1 hedgeInstrumentStarts.Add(frontDateTime.AddMonths(-duration)); hedgeInstrumentEnds.Add(endDateTime.AddMonths(duration)); quoteRatios.Add(-3); hedgeRatios.Add(1); caseNumber++; break; case 2: // 4 cases in this situation. // 1: (2,4) to (4,6) 1:-1=1 hedgeInstrumentStarts.Add(frontDateTime.AddMonths(duration)); hedgeInstrumentEnds.Add(endDateTime.AddMonths(duration)); quoteRatios.Add(1); hedgeRatios.Add(-1); caseNumber++; // 2: (2,4) to (3,4) 1:-2=1 hedgeInstrumentStarts.Add(frontDateTime.AddMonths(duration / 2)); hedgeInstrumentEnds.Add(endDateTime); quoteRatios.Add(1); hedgeRatios.Add(-2); caseNumber++; // 3: (2,4) to (0,2) -1:1=1 hedgeInstrumentStarts.Add(frontDateTime.AddMonths(-duration)); hedgeInstrumentEnds.Add(endDateTime.AddMonths(-duration)); quoteRatios.Add(-1); hedgeRatios.Add(1); caseNumber++; // 4: (2,4) to (2,3) -1:2=1 hedgeInstrumentStarts.Add(frontDateTime); hedgeInstrumentEnds.Add(endDateTime.AddMonths(-duration / 2)); quoteRatios.Add(-1); hedgeRatios.Add(2); caseNumber++; break; case 3: // 3 cases in this situation. // 1: (3,6) to (6,9) 1:-1=1 hedgeInstrumentStarts.Add(frontDateTime.AddMonths(duration)); hedgeInstrumentEnds.Add(endDateTime.AddMonths(duration)); quoteRatios.Add(1); hedgeRatios.Add(-1); caseNumber++; // 2: (3,6) to (0,3) -1:1=1 hedgeInstrumentStarts.Add(frontDateTime.AddMonths(-duration)); hedgeInstrumentEnds.Add(endDateTime.AddMonths(-duration)); quoteRatios.Add(-1); hedgeRatios.Add(1); caseNumber++; // 3: (3,6) to (4,5) 1:-3=1 hedgeInstrumentStarts.Add(frontDateTime.AddMonths(duration / 3)); hedgeInstrumentEnds.Add(endDateTime.AddMonths(-duration / 3)); quoteRatios.Add(1); hedgeRatios.Add(-3); caseNumber++; break; default: break; } bool isFirstHedgeOption = true; for (int hedgeIndex = 0; hedgeIndex < caseNumber; ++hedgeIndex) { string hedgeInstrumentSeriesName = string.Format("Calendar: 1x{0} {1}:-1x{2}", productName, hedgeInstrumentStarts[hedgeIndex].ToString("MMMyy"), hedgeInstrumentEnds[hedgeIndex].ToString("MMMyy")); InstrumentName hedgeInstrument = new InstrumentName(quoteInstrument.Product, hedgeInstrumentSeriesName); ResultingInstrument resultingInstrument; if (QTMath.TryComposeResultingInstrument(quoteInstrument, quoteRatios[hedgeIndex], hedgeInstrument, hedgeRatios[hedgeIndex], m_Log, out resultingInstrument)) { HedgeOption hedgeOption = new HedgeOption(); hedgeOption.QuoteInstrument = quoteInstrument; hedgeOption.QuoteWeight = quoteRatios[hedgeIndex]; hedgeOption.ResultingInstrument = resultingInstrument; hedgeOption.ResultingWeight = 1; hedgeOption.TryAddInstrumentAndWeight(hedgeInstrument, hedgeRatios[hedgeIndex]); hedgeOptions.Add(hedgeOption); } else { m_Log.NewEntry(LogLevel.Error, "Failed to compose resulting instrument for quote {0} and hedge {1}.", quoteInstrument, hedgeInstrument); return(isSuccess); } if (isFirstHedgeOption) { isFirstHedgeOption = false; } else { hedgeOptionsBuilder.Append("|"); } // Consider the target example: // 1x{1xGE_U4.-1xGE_Z4}-1x{1xGE_Z4.-1xGE_H5}=1x{1xGE_U4.-2xGE_Z4.1xGE_H5}|-1x{1xGE_U4.-1xGE_Z4}+1x{1xGE_M4.-1xGE_U4}=1x{1xGE_M4.-2xGE_U4.1xGE_Z4} // |2x{1xGE_U4.-1xGE_Z4}-1x{1xGE_U4.-1xGE_H5}=1x{1xGE_U4.-2xGE_Z4.1xGE_H5}|-2x{1xGE_U4.-1xGE_Z4}+1x{1xGE_M4.-1xGE_Z4}=1x{1xGE_M4.-2xGE_U4.1xGE_Z4} // |-3x{1xGE_U4.-1xGE_Z4}+1x{1xGE_M4.-1xGE_H5}=1x{1xGE_M4.-3xGE_U4.3xGE_Z4.-1xGE_H5} string quoteInstrumentDatabaseName; string hedgeInstrumentDatabaseName; if (!QTMath.TryConvertInstrumentNameToInstrumentNameDatabase(quoteInstrument, m_Log, out quoteInstrumentDatabaseName)) { m_Log.NewEntry(LogLevel.Error, "Failed to get instrument database name for instrument {0}.", quoteInstrument); return(isSuccess); } if (!QTMath.TryConvertInstrumentNameToInstrumentNameDatabase(hedgeInstrument, m_Log, out hedgeInstrumentDatabaseName)) { m_Log.NewEntry(LogLevel.Error, "Failed to get instrument database name for instrument {0}.", hedgeInstrument); return(isSuccess); } string hedgeWeightWithSigned = hedgeRatios[hedgeIndex] > 0 ? string.Format("+{0}", hedgeRatios[hedgeIndex]) : (hedgeRatios[hedgeIndex].ToString()); hedgeOptionsBuilder.AppendFormat("{0}x{{{1}}}{2}x{{{3}}}=1x{{{4}}}", quoteRatios[hedgeIndex], quoteInstrumentDatabaseName, hedgeWeightWithSigned, hedgeInstrumentDatabaseName, resultingInstrument.ResultingInstrumentNameDataBase); } hedgeOptionsString = hedgeOptionsBuilder.ToString(); isSuccess = true; } else { m_Log.NewEntry(LogLevel.Error, "Duration smaller or equal than 0 for instrument {0}.", quoteInstrument); return(isSuccess); } } else { m_Log.NewEntry(LogLevel.Error, "Series name does not have two month years for this instrument {0}.", quoteInstrument); return(isSuccess); } } else { m_Log.NewEntry(LogLevel.Error, "No product type is handled for this instrument {0}.", quoteInstrument); return(isSuccess); } break; default: break; } return(isSuccess); }
// ***************************************************************** // **** Private Methods **** // ***************************************************************** // // // // /// <summary> /// This function will generate resulting instruments for the quote instrument. /// Also, it will generate the ratios and hedge instruments in that resulting instrument. /// </summary> /// <param name="instrumentInfoItem"></param> /// <returns></returns> public bool TryGenerateHedgeOptions(InstrumentName quoteInstrument, InstrumentInfoItem instrumentInfoItem, HedgeOptions hedgeOptions) { bool isSuccess = false; string hedgeOptionString = instrumentInfoItem.HedgeOptions; // Consider the target example: // 1x{1xGE_U4.-1xGE_Z4}-1x{1xGE_Z4.-1xGE_H5}=1x{1xGE_U4.-2xGE_Z4.1xGE_H5}|-1x{1xGE_U4.-1xGE_Z4}+1x{1xGE_M4.-1xGE_U4}=1x{1xGE_M4.-2xGE_U4.1xGE_Z4} // |2x{1xGE_U4.-1xGE_Z4}-1x{1xGE_U4.-1xGE_H5}=1x{1xGE_U4.-2xGE_Z4.1xGE_H5}|-2x{1xGE_U4.-1xGE_Z4}+1x{1xGE_M4.-1xGE_Z4}=1x{1xGE_M4.-2xGE_U4.1xGE_Z4} // |-3x{1xGE_U4.-1xGE_Z4}+1x{1xGE_M4.-1xGE_H5}=1x{1xGE_M4.-3xGE_U4.3xGE_Z4.-1xGE_H5} // First step: Parse different hedges and resulting instruments. char seperator = '|'; string[] hedgeOptionUnits = hedgeOptionString.Split(new char[] { seperator }, StringSplitOptions.RemoveEmptyEntries); if (hedgeOptionUnits.Length > 0) { string exchangeName = quoteInstrument.Product.Exchange; List <string> matchedResults = new List <string>(); foreach (string hedgeOptionUnit in hedgeOptionUnits) { // Second step: Parse hedge instruments and resulting instruments. // Target: 1x{1xGE_U4.-1xGE_Z4}-1x{1xGE_Z4.-1xGE_H5}=1x{1xGE_U4.-2xGE_Z4.1xGE_H5} seperator = '='; string[] hedgeAndResultingInstruments = hedgeOptionUnit.Split(new char[] { seperator }, StringSplitOptions.RemoveEmptyEntries); if (hedgeAndResultingInstruments.Length == 2) { HedgeOption hedgeOption = null; bool isQuoteInstrument = false; // Quote instrument always the first. // Third step: Parse hedge instruments further by their weights. // Target: 1x{1xGE_U4.-1xGE_Z4}-1x{1xGE_Z4.-1xGE_H5} string hedgeInstrumentsPart = hedgeAndResultingInstruments[0]; string pattern = @"-?\d+x{[^}]+}"; matchedResults.Clear(); MatchCollection matchCollection = Regex.Matches(hedgeInstrumentsPart, pattern); foreach (Match match in matchCollection) { string matchedValue = match.Value; matchedResults.Add(matchedValue); } // Fourth step: Parse weight and instrument name for each hedge instrument. // Target: 1x{1xGE_U4.-1xGE_Z4} foreach (string matchedInstrument in matchedResults) { int weight = 0; // 1. Weight: string firstPart = matchedInstrument.Substring(0, matchedInstrument.IndexOf('x')); if (int.TryParse(firstPart, out weight) && weight != 0) { // 2. Name: pattern = @"\{(?<hedgeName>\S+)\}"; Match match = Regex.Match(matchedInstrument, pattern); string name = match.Groups["hedgeName"].Value; // Fifth step: Parse instrument name out. //// There may be alternative way to do it. The data base contains the instrument name TT and we may use that. // Target: 1xGE_U4.-1xGE_Z4 InstrumentName instrumentComposed = quoteInstrument; if (QTMath.TryComposeInstrumentName(name, quoteInstrument, m_Log, out instrumentComposed)) { if (!isQuoteInstrument) { hedgeOption = new HedgeOption(); hedgeOption.QuoteInstrument = instrumentComposed; hedgeOption.QuoteWeight = weight; hedgeOption.TryAddInstrumentAndWeight(instrumentComposed, weight); isQuoteInstrument = true; } else { if (instrumentComposed != quoteInstrument) { hedgeOption.TryAddInstrumentAndWeight(instrumentComposed, weight); } else { m_Log.NewEntry(LogLevel.Error, "instrument composed same as quote instrument {0}.", instrumentComposed); return(isSuccess); } } } else { m_Log.NewEntry(LogLevel.Error, "Failed to compose instrument name for string {0}.", name); return(isSuccess); } } else { m_Log.NewEntry(LogLevel.Error, "instrument weight parse failed for {0}.", matchedInstrument); return(isSuccess); } } // If the hedge option exists. if (hedgeOption != null) { // Sixth step: Continue to read the resulting instrument if hedge option is valid. // Target: 1x{1xGE_U4.-2xGE_Z4.1xGE_H5} string resultingInstrumentPart = hedgeAndResultingInstruments[1]; // 1.Weight: string weightString = resultingInstrumentPart.Substring(0, resultingInstrumentPart.IndexOf('x')); int resultingWeight = 0; if (int.TryParse(weightString, out resultingWeight) && resultingWeight != 0) { // 2.Name: pattern = @"\{(?<resultingName>\S+)\}"; Match match = Regex.Match(resultingInstrumentPart, pattern); string resultingInstrumentName = match.Groups["resultingName"].Value; ResultingInstrument resultingInstrument = new ResultingInstrument(); resultingInstrument.ResultingInstrumentNameDataBase = resultingInstrumentName; hedgeOption.ResultingInstrument = resultingInstrument; hedgeOption.ResultingWeight = resultingWeight; // 3. Compose resulting instrument name: InstrumentName instrumentComposed = quoteInstrument; if (QTMath.TryComposeInstrumentName(resultingInstrumentName, quoteInstrument, m_Log, out instrumentComposed)) { resultingInstrument.ResultingInstrumentName = instrumentComposed; resultingInstrument.ResultingInstrumentNameTT = instrumentComposed.FullName; if (!hedgeOptions.TryAddHedgeOption(hedgeOption)) { m_Log.NewEntry(LogLevel.Error, "Failed to add hedge option for instrument {0}.", quoteInstrument); return(isSuccess); } } else { m_Log.NewEntry(LogLevel.Error, "Failed to compose instrument name for string {0}.", resultingInstrumentName); return(isSuccess); } } } } else { m_Log.NewEntry(LogLevel.Error, "hedge and resulting instruments parse failed for string {0}.", hedgeOptionUnit); return(isSuccess); } } isSuccess = true; } else { m_Log.NewEntry(LogLevel.Error, "hedge options parse failed for string {0}.", hedgeOptionString); return(isSuccess); } return(isSuccess); }