19 using System.Globalization;
21 using System.Collections.Generic;
34 private static DateTime TodayUtc = DateTime.UtcNow;
103 var doubleDigitYear =
char.IsDigit(ticker.Substring(ticker.Length - 2, 1)[0]);
104 var doubleDigitOffset = doubleDigitYear ? 1 : 0;
106 var expirationDayOffset = 0;
107 var expirationDay = 1;
108 if (ticker.Length > 4 + doubleDigitOffset)
110 var potentialExpirationDay = ticker.Substring(ticker.Length - 4 - doubleDigitOffset, 2);
111 var containsExpirationDay =
char.IsDigit(potentialExpirationDay[0]) &&
char.IsDigit(potentialExpirationDay[1]);
112 expirationDayOffset = containsExpirationDay ? 2 : 0;
113 if (containsExpirationDay && !
int.TryParse(potentialExpirationDay, out expirationDay))
119 var expirationYearString = ticker.Substring(ticker.Length - 1 - doubleDigitOffset, 1 + doubleDigitOffset);
120 var expirationMonthString = ticker.Substring(ticker.Length - 2 - doubleDigitOffset, 1);
121 var underlyingString = ticker.Substring(0, ticker.Length - 2 - doubleDigitOffset - expirationDayOffset);
123 int expirationYearShort;
125 if (!
int.TryParse(expirationYearString, out expirationYearShort))
130 if (!_futuresMonthCodeLookup.ContainsKey(expirationMonthString))
135 var expirationMonth = _futuresMonthCodeLookup[expirationMonthString];
139 Underlying = underlyingString,
140 ExpirationYearShort = expirationYearShort,
141 ExpirationYearShortLength = expirationYearString.Length,
142 ExpirationMonth = expirationMonth,
143 ExpirationDay = expirationDay
161 var underlying = parsed.Underlying;
162 var expirationMonth = parsed.ExpirationMonth;
163 var expirationYear = GetExpirationYear(futureYear, parsed);
167 Log.
Debug($
@"SymbolRepresentation.ParseFutureSymbol(): {
168 Messages.SymbolRepresentation.FailedToGetMarketForTickerAndUnderlying(ticker, underlying)}");
173 var expiryDate = expiryFunc(
new DateTime(expirationYear, expirationMonth, 1));
185 var split = ticker.Split(
' ');
186 if (split.Length != 2)
196 ticker = parsed.Underlying;
199 if (split[1][0] ==
'P' || split[1][0] ==
'p')
203 else if (split[1][0] ==
'C' || split[1][0] ==
'c')
211 var strike = split[1].Substring(1);
213 if (parsed.ExpirationYearShort < 10)
215 parsed.ExpirationYearShort += 20;
217 var expirationYearParsed = 2000 + parsed.ExpirationYearShort;
219 var expirationDate =
new DateTime(expirationYearParsed, parsed.ExpirationMonth, 1);
221 var strikePrice = decimal.Parse(strike, NumberStyles.Any, CultureInfo.InvariantCulture);
226 Log.
Debug($
"SymbolRepresentation.ParseFutureOptionSymbol(): {Messages.SymbolRepresentation.NoMarketFound(futureTicker)}");
240 strikePrice / strikeScale,
253 public static string GenerateFutureTicker(
string underlying, DateTime expiration,
bool doubleDigitsYear =
true,
bool includeExpirationDate =
true)
255 var year = doubleDigitsYear ? expiration.Year % 100 : expiration.Year % 10;
256 var month = expiration.Month;
259 if (contractMonthDelta < 0)
263 var expirationMonth = expiration.AddDays(-(expiration.Day - 1))
264 .AddMonths(contractMonthDelta);
266 month = expirationMonth.Month;
267 year = doubleDigitsYear ? expirationMonth.Year % 100 : expirationMonth.Year % 10;
271 month += contractMonthDelta;
284 var expirationDay = includeExpirationDate ? $
"{expiration.Day:00}" :
string.Empty;
286 return $
"{underlying}{expirationDay}{_futuresMonthLookup[month]}{year}";
299 throw new ArgumentException(
317 if (underlying.Length > 5) underlying +=
" ";
318 return Invariant($
"{underlying,-6}{expiration.ToStringInvariant(DateFormat.SixCharacter)}{right.ToStringPerformance()[0]}{(strikePrice * 1000m):00000000}");
343 var optionTicker = ticker.Substring(0, 6).Trim();
346 if (ticker[12] ==
'C' || ticker[12] ==
'c')
350 else if (ticker[12] ==
'P' || ticker[12] ==
'p')
358 var strike =
Parse.
Decimal(ticker.Substring(13, 8)) / 1000m;
372 throw new NotImplementedException($
"ParseOptionTickerOSI(): {Messages.SymbolRepresentation.SecurityTypeNotImplemented(securityType)}");
387 var letter = _optionSymbology.Where(x => x.Value.Item2 == symbol.
ID.
OptionRight && x.Value.Item1 == symbol.
ID.
Date.Month).Select(x => x.Key).Single();
388 var twoYearDigit = symbol.
ID.
Date.ToString(
"yy");
389 return $
"{SecurityIdentifier.Ticker(symbol.Underlying, symbol.ID.Date)}{twoYearDigit}{symbol.ID.Date.Day:00}{letter}{symbol.ID.StrikePrice.ToStringInvariant()}";
400 var letterRange = _optionSymbology.Keys
403 var optionTypeDelimiter = ticker.LastIndexOfAny(letterRange);
404 var strikePriceString = ticker.Substring(optionTypeDelimiter + 1, ticker.Length - optionTypeDelimiter - 1);
406 var lookupResult = _optionSymbology[ticker[optionTypeDelimiter].ToStringInvariant()];
407 var month = lookupResult.Item1;
408 var optionRight = lookupResult.Item2;
410 var dayString = ticker.Substring(optionTypeDelimiter - 2, 2);
411 var yearString = ticker.Substring(optionTypeDelimiter - 4, 2);
412 var underlying = ticker.Substring(0, optionTypeDelimiter - 4);
416 if (!Decimal.TryParse(strikePriceString, NumberStyles.Any, CultureInfo.InvariantCulture, out strikePrice))
423 if (!
int.TryParse(dayString, out day))
430 if (!
int.TryParse(yearString, out year))
435 var expirationDate =
new DateTime(2000 + year, month, day);
439 Underlying = underlying,
441 OptionStrike = strikePrice,
442 ExpirationDate = expirationDate
448 private static Dictionary<string, Tuple<int, OptionRight>> _optionSymbology =
new Dictionary<string, Tuple<int, OptionRight>>
466 private static IReadOnlyDictionary<string, int> _futuresMonthCodeLookup =
new Dictionary<string, int>
482 private static IReadOnlyDictionary<int, string> _futuresMonthLookup = _futuresMonthCodeLookup.ToDictionary(kv => kv.Value, kv => kv.Key);
491 private static int GetExpirationYear(
int? futureYear, FutureTickerProperties parsed)
493 if(futureYear.HasValue)
495 var referenceYear = 1900 + parsed.ExpirationYearShort;
496 while(referenceYear < futureYear.Value)
501 return referenceYear;
504 var currentYear = DateTime.UtcNow.Year;
505 if (parsed.ExpirationYearShortLength > 1)
508 return 2000 + parsed.ExpirationYearShort;
511 var baseYear = ((int)Math.Round(currentYear / 10.0)) * 10 + parsed.ExpirationYearShort;
512 while (baseYear < currentYear)