package jtrade;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import jtrade.util.DateTimeRange;
import org.joda.time.DateTime;
import org.joda.time.DateTimeConstants;
import org.joda.time.Months;
import org.joda.time.MutableDateTime;
import org.joda.time.ReadableDateTime;
public class SymbolFactory {
public static List<Symbol> forex = new ArrayList<Symbol>();
public static List<Symbol> futures = new ArrayList<Symbol>();
public static Map<String, Symbol> symbols = new TreeMap<String, Symbol>();
static {
symbols.put("OMXS30-OMS-SEK-INDEX", new Symbol("OMXS30", "OMS", "SEK", "INDEX", 100, 0.25));
symbols.put("SPX-CBOE-USD-INDEX", new Symbol("SPX-CBOE-USD-INDEX"));
symbols.put("INDU-NYSE-USD-INDEX", new Symbol("INDU-NYSE-USD-INDEX"));
symbols.put("COMP-NASDAQ-USD-INDEX", new Symbol("COMP-NASDAQ-USD-INDEX"));
symbols.put("Z-LIFFE-GBP-INDEX", new Symbol("Z-LIFFE-GBP-INDEX"));
symbols.put("DAX-DTB-EUR-INDEX", new Symbol("DAX-DTB-EUR-INDEX"));
symbols.put("ESTX50-DTB-EUR-INDEX", new Symbol("ESTX50-DTB-EUR-INDEX"));
symbols.put("CAC40-MONEP-EUR-INDEX", new Symbol("CAC40-MONEP-EUR-INDEX"));
symbols.put("N225-OSE.JPN-JPY-INDEX", new Symbol("N225-OSE.JPN-JPY-INDEX"));
symbols.put("VIX-CBOE-USD-INDEX", new Symbol("VIX-CBOE-USD-INDEX"));
symbols.put("HSI-HKFE-HKD-INDEX", new Symbol("HSI-HKFE-HKD-INDEX"));
futures.add(new Symbol("OMXS30", "OMS", "SEK", "FUTURE", 100, 0.25));
futures.add(new Symbol("ES", "GLOBEX", "USD", "FUTURE", 50, 0.25));
futures.add(new Symbol("Z", "LIFFE", "GBP", "FUTURE", 10, 0.5));
futures.add(new Symbol("DAX", "DTB", "EUR", "FUTURE", 25, 0.5));
futures.add(new Symbol("ESTX50", "DTB", "EUR", "FUTURE", 10, 1.0));
futures.add(new Symbol("CAC40", "MONEP", "EUR", "FUTURE", 10, 0.5));
futures.add(new Symbol("WTI", "IPE", "USD", "FUTURE", 1000, 0.01));
futures.add(new Symbol("COIL", "IPE", "USD", "FUTURE", 100, 0.25));
futures.add(new Symbol("GC", "NYMEX", "USD", "FUTURE", 100, 0.1));
futures.add(new Symbol("CL", "NYMEX", "USD", "FUTURE", 1000, 0.01));
for (Symbol f : futures) {
symbols.put(f.getFullCode(), f);
}
for (Iterator<DateTime> dates = new DateTimeRange(new DateTime().withDayOfYear(1).minusYears(2), new DateTime().withDayOfYear(1).plusYears(2))
.iterator(Months.ONE); dates.hasNext();) {
DateTime dt = dates.next();
for (Symbol f : futures) {
Symbol s = getMostLiquidFutureSymbol(f, dt);
symbols.put(s.getFullCode(), s);
}
}
forex.add(new Symbol("EUR", "IDEALPRO", "USD", "CASH", 1, 0.0001));
forex.add(new Symbol("USD", "IDEALPRO", "SEK", "CASH", 1, 0.0001));
forex.add(new Symbol("USD", "IDEALPRO", "CHF", "CASH", 1, 0.0001));
forex.add(new Symbol("USD", "IDEALPRO", "CAD", "CASH", 1, 0.0001));
forex.add(new Symbol("USD", "IDEALPRO", "HKD", "CASH", 1, 0.0001));
forex.add(new Symbol("USD", "IDEALPRO", "SGD", "CASH", 1, 0.0001));
forex.add(new Symbol("USD", "IDEALPRO", "RUB", "CASH", 1, 0.0001));
forex.add(new Symbol("USD", "IDEALPRO", "CNH", "CASH", 1, 0.0001));
forex.add(new Symbol("USD", "IDEALPRO", "CZK", "CASH", 1, 0.0001));
forex.add(new Symbol("USD", "IDEALPRO", "HUF", "CASH", 1, 0.0001));
forex.add(new Symbol("USD", "IDEALPRO", "ILS", "CASH", 1, 0.0001));
forex.add(new Symbol("USD", "IDEALPRO", "DKK", "CASH", 1, 0.0001));
forex.add(new Symbol("USD", "IDEALPRO", "NOK", "CASH", 1, 0.0001));
forex.add(new Symbol("USD", "IDEALPRO", "PLN", "CASH", 1, 0.0001));
forex.add(new Symbol("USD", "IDEALPRO", "MXN", "CASH", 1, 0.0001));
forex.add(new Symbol("USD", "IDEALPRO", "JPY", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "USD", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "GBP", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "SEK", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "CHF", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "CAD", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "AUD", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "HKD", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "SGD", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "RUB", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "CNH", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "CZK", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "HUF", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "ILS", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "DKK", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "NOK", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "PLN", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "MXN", "CASH", 1, 0.0001));
forex.add(new Symbol("EUR", "IDEALPRO", "JPY", "CASH", 1, 0.0001));
forex.add(new Symbol("GBP", "IDEALPRO", "USD", "CASH", 1, 0.0001));
forex.add(new Symbol("GBP", "IDEALPRO", "NZD", "CASH", 1, 0.0001));
forex.add(new Symbol("GBP", "IDEALPRO", "SEK", "CASH", 1, 0.0001));
forex.add(new Symbol("GBP", "IDEALPRO", "CHF", "CASH", 1, 0.0001));
forex.add(new Symbol("GBP", "IDEALPRO", "CAD", "CASH", 1, 0.0001));
forex.add(new Symbol("GBP", "IDEALPRO", "AUD", "CASH", 1, 0.0001));
forex.add(new Symbol("GBP", "IDEALPRO", "HKD", "CASH", 1, 0.0001));
forex.add(new Symbol("GBP", "IDEALPRO", "CNH", "CASH", 1, 0.0001));
forex.add(new Symbol("GBP", "IDEALPRO", "DKK", "CASH", 1, 0.0001));
forex.add(new Symbol("GBP", "IDEALPRO", "NOK", "CASH", 1, 0.0001));
forex.add(new Symbol("GBP", "IDEALPRO", "MXN", "CASH", 1, 0.0001));
forex.add(new Symbol("GBP", "IDEALPRO", "JPY", "CASH", 1, 0.0001));
forex.add(new Symbol("CAD", "IDEALPRO", "CHF", "CASH", 1, 0.0001));
forex.add(new Symbol("CAD", "IDEALPRO", "HKD", "CASH", 1, 0.0001));
forex.add(new Symbol("CAD", "IDEALPRO", "JPY", "CASH", 1, 0.0001));
forex.add(new Symbol("CAD", "IDEALPRO", "CNH", "CASH", 1, 0.0001));
forex.add(new Symbol("AUD", "IDEALPRO", "USD", "CASH", 1, 0.0001));
forex.add(new Symbol("AUD", "IDEALPRO", "CHF", "CASH", 1, 0.0001));
forex.add(new Symbol("AUD", "IDEALPRO", "HKD", "CASH", 1, 0.0001));
forex.add(new Symbol("AUD", "IDEALPRO", "JPY", "CASH", 1, 0.0001));
forex.add(new Symbol("AUD", "IDEALPRO", "CAD", "CASH", 1, 0.0001));
forex.add(new Symbol("AUD", "IDEALPRO", "CNH", "CASH", 1, 0.0001));
forex.add(new Symbol("AUD", "IDEALPRO", "NZD", "CASH", 1, 0.0001));
forex.add(new Symbol("AUD", "IDEALPRO", "SGD", "CASH", 1, 0.0001));
forex.add(new Symbol("CHF", "IDEALPRO", "JPY", "CASH", 1, 0.0001));
forex.add(new Symbol("CHF", "IDEALPRO", "CNH", "CASH", 1, 0.0001));
forex.add(new Symbol("CHF", "IDEALPRO", "DKK", "CASH", 1, 0.0001));
forex.add(new Symbol("CHF", "IDEALPRO", "NOK", "CASH", 1, 0.0001));
forex.add(new Symbol("CHF", "IDEALPRO", "SEK", "CASH", 1, 0.0001));
for (Symbol f : forex) {
symbols.put(f.getFullCode(), f);
}
}
public static List<Symbol> getFutures() {
return new ArrayList<Symbol>(futures);
}
public static List<Symbol> getSymbols(List<String> symbols) {
return getSymbols(symbols.toArray(new String[symbols.size()]));
}
public static List<Symbol> getSymbols(String... symbol) {
List<Symbol> result = new ArrayList<Symbol>(symbol.length);
for (String s : symbol) {
result.add(getSymbol(s));
}
return result;
}
public static List<Symbol> getExchangeSymbols(String exchange) {
List<Symbol> result = new ArrayList<Symbol>();
for (Symbol s : symbols.values()) {
if (s.getExchange().equals(exchange)) {
result.add(s);
}
}
return result;
}
public static Symbol getSymbol(String fullCode) {
Symbol s = symbols.get(fullCode);
if (s == null) {
s = new Symbol(fullCode);
symbols.put(fullCode, s);
}
return s;
}
public static Symbol getCash(String currency, String baseCurrency) {
return getSymbol(new StringBuilder().append(currency).append("-IDEALPRO-").append(baseCurrency).append("-CASH").toString());
}
public static Symbol getSP500Index() {
return symbols.get("SPX-CBOE-USD-INDEX");
}
public static Symbol getDowIndex() {
return symbols.get("INDU-NYSE-USD-INDEX");
}
public static Symbol getNasdaqIndex() {
return symbols.get("COMP-NASDAQ-USD-INDEX");
}
public static Symbol getNikkeiIndex() {
return symbols.get("N225-OSE.JPN-JPY-INDEX");
}
public static Symbol getHangSengIndex() {
return symbols.get("HSI-HKFE-HKD-INDEX");
}
public static Symbol getVixIndex() {
return symbols.get("VIX-CBOE-USD-INDEX");
}
public static Symbol getDAXIndex() {
return symbols.get("DAX-DTB-EUR-INDEX");
}
public static Symbol getESTX50Index() {
return symbols.get("ESTX50-DTB-EUR-INDEX");
}
public static Symbol getFTSEIndex() {
return symbols.get("Z-LIFFE-GBP-INDEX");
}
public static Symbol getOMXS30Index() {
return symbols.get("OMXS30-OMS-SEK-INDEX");
}
public static Symbol getCAC40Index() {
return symbols.get("CAC40-MONEP-EUR-INDEX");
}
public static Symbol getMostLiquidFutureSymbol(Symbol s, DateTime date) {
if (!s.isFuture()) {
return s;
}
if (s.getCode().equals("ES")) {
return getESFutureSymbol(s, date);
}
if (s.getCode().equals("OMXS30")) {
return getOMXFutureSymbol(s, date);
}
if (s.getCode().equals("DAX")) {
return getDAXFutureSymbol(s, date);
}
if (s.getCode().equals("ESTX50")) {
return getESTX50FutureSymbol(s, date);
}
if (s.getCode().equals("Z")) {
return getZFutureSymbol(s, date);
}
if (s.getCode().equals("CAC40")) {
return getCAC40FutureSymbol(s, date);
}
if (s.getCode().equals("VIX")) {
return getVIXFutureSymbol(s, date);
}
if (s.getCode().equals("COIL")) {
return getCOILFutureSymbol(s, date);
}
if (s.getCode().equals("WTI")) {
return getWTIFutureSymbol(s, date);
}
if (s.getCode().equals("GC")) {
return getGCFutureSymbol(s, date);
}
if (s.getCode().equals("CL")) {
return getCLFutureSymbol(s, date);
}
if (s.getExchange().equals("OMX")) {
return getOMXFutureSymbol(s, date);
}
if (s.getExchange().equals("ONE")) {
return getONEFutureSymbol(s, date);
}
throw new IllegalArgumentException("Unsupported future: " + s.toString());
}
public static Symbol getOMXS30FutureSymbol(DateTime date) {
return getOMXFutureSymbol(null, date);
}
public static Symbol getOMXS30FutureSymbol(Symbol s, DateTime date) {
return getOMXFutureSymbol(s, date);
}
public static Symbol getOMXFutureSymbol(DateTime date) {
return getOMXFutureSymbol(null, date);
}
public static Symbol getOMXFutureSymbol(Symbol s, DateTime date) {
DateTime expiryDate = null;
if (date.isBefore(1208383200000L)) { // 2008-04-17
expiryDate = getMostLiquidMonthlyExpiry(date, 2, 4);
if (expiryDate.equals(new DateTime(2007, 6, 22, 0, 0, 0, 0))) {
expiryDate = expiryDate.minusDays(1);
}
} else if (date.isBefore(1293836400000L)) { // 2011-01-01
expiryDate = getMostLiquidMonthlyExpiry(date, 2, 3);
// Strange hack for these dates
if (expiryDate.equals(new DateTime(2008, 6, 20, 0, 0, 0, 0))) {
expiryDate = expiryDate.minusDays(1);
} else if (expiryDate.equals(new DateTime(2009, 1, 16, 0, 0, 0, 0))) {
expiryDate = expiryDate.plusDays(7);
} else if (expiryDate.equals(new DateTime(2009, 6, 19, 0, 0, 0, 0))) {
expiryDate = expiryDate.minusDays(1);
} else if (expiryDate.equals(new DateTime(2010, 1, 15, 0, 0, 0, 0))) {
expiryDate = expiryDate.plusDays(7);
}
} else if (date.isBefore(1371765600000L)) { // 2013-06-21
expiryDate = getMostLiquidMonthlyExpiry(date, 2, 3);
// Strange hack for these dates
if (expiryDate.getMillis() == 1371765600000L) {
expiryDate = expiryDate.minusDays(1);
}
} else {
expiryDate = getMostLiquidMonthlyExpiry(date, 2, 3);
}
if (s != null && expiryDate.equals(s.getExpiry())) {
return s;
}
// String code = "OMXS30" + (expiryDate.getYearOfCentury() % 10) +
// (char)
// (64 + expiryDate.getMonthOfYear());
// return new Symbol(code, "OMS", "SEK", expiryDate);
return new Symbol(s != null ? s.getCode() : "OMXS30", "OMS", "SEK", expiryDate, 100, 0.25);
}
public static Symbol getESFutureSymbol(DateTime date) {
return getESFutureSymbol(null, date);
}
public static Symbol getESFutureSymbol(Symbol s, DateTime date) {
DateTime expiryDate = getMostLiquidQuarterlyExpiry(date, 8);
if (s != null && expiryDate.equals(s.getExpiry())) {
return s;
}
return new Symbol("ES", "GLOBEX", "USD", expiryDate, 50, 0.25);
}
public static Symbol getDAXFutureSymbol(DateTime date) {
return getDAXFutureSymbol(null, date);
}
public static Symbol getDAXFutureSymbol(Symbol s, DateTime date) {
DateTime expiryDate = getMostLiquidQuarterlyExpiry(date, 8);
if (s != null && expiryDate.equals(s.getExpiry())) {
return s;
}
return new Symbol("DAX", "DTB", "EUR", getMostLiquidQuarterlyExpiry(date, 8), 25, 0.5);
}
public static Symbol getESTX50FutureSymbol(DateTime date) {
return getESTX50FutureSymbol(null, date);
}
public static Symbol getESTX50FutureSymbol(Symbol s, DateTime date) {
DateTime expiryDate = getMostLiquidQuarterlyExpiry(date, 8);
if (s != null && expiryDate.equals(s.getExpiry())) {
return s;
}
return new Symbol("ESTX50", "DTB", "EUR", getMostLiquidQuarterlyExpiry(date, 8), 10, 1.0);
}
public static Symbol getZFutureSymbol(DateTime date) {
return getZFutureSymbol(null, date);
}
public static Symbol getZFutureSymbol(Symbol s, DateTime date) {
DateTime expiryDate = getMostLiquidQuarterlyExpiry(date, 8);
if (s != null && expiryDate.equals(s.getExpiry())) {
return s;
}
return new Symbol("Z", "LIFFE", "GBP", expiryDate, 10, 0.5);
}
public static Symbol getCAC40FutureSymbol(DateTime date) {
return getCAC40FutureSymbol(null, date);
}
public static Symbol getCAC40FutureSymbol(Symbol s, DateTime date) {
DateTime expiryDate = getMostLiquidMonthlyExpiry(date, 7, 3);
if (s != null && expiryDate.equals(s.getExpiry())) {
return s;
}
return new Symbol("CAC40", "MONEP", "EUR", expiryDate, 10, 0.5);
}
public static Symbol getVIXFutureSymbol(DateTime date) {
return getVIXFutureSymbol(null, date);
}
public static Symbol getVIXFutureSymbol(Symbol s, DateTime date) {
DateTime expiryDate = getMostLiquidVIXMonthlyExpiry(date);
if (s != null && expiryDate.equals(s.getExpiry())) {
return s;
}
return new Symbol("VIX", "CFE", "USD", expiryDate, 1000, 0.05);
}
public static Symbol getCOILFutureSymbol(DateTime date) {
return getCOILFutureSymbol(null, date);
}
public static Symbol getCOILFutureSymbol(Symbol s, DateTime date) {
// Get 15th day preceding the first of the contract month
MutableDateTime expiryDate = new MutableDateTime(date);
expiryDate.setMillisOfDay(0);
expiryDate.setMonthOfYear(expiryDate.getMonthOfYear() + (expiryDate.getMonthOfYear() < 12 ? 1 : 0));
expiryDate.setDayOfMonth(1);
expiryDate.addDays(-15);
if (expiryDate.getDayOfWeek() == DateTimeConstants.SATURDAY) {
expiryDate.addDays(-2);
} else if (expiryDate.getDayOfWeek() == DateTimeConstants.SUNDAY) {
expiryDate.addDays(-3);
} else if (expiryDate.getDayOfWeek() == DateTimeConstants.MONDAY) {
expiryDate.addDays(-3);
} else {
expiryDate.addDays(-1);
}
if (s != null && expiryDate.equals(s.getExpiry())) {
return s;
}
return new Symbol("COIL", "IPE", "USD", expiryDate.toDateTime(), 1000, 0.01);
}
public static Symbol getWTIFutureSymbol(DateTime date) {
return getWTIFutureSymbol(null, date);
}
public static Symbol getWTIFutureSymbol(Symbol s, DateTime date) {
DateTime expiryDate = getMostLiquidMonthlyExpiry(date, 7, 3);
if (s != null && expiryDate.equals(s.getExpiry())) {
return s;
}
s = symbols.get(s.getFullCode());
return new Symbol("WTI", "IPE", "USD", expiryDate, 1000, 0.01);
}
public static Symbol getGCFutureSymbol(DateTime date) {
return getGCFutureSymbol(null, date);
}
public static Symbol getGCFutureSymbol(Symbol s, DateTime date) {
// Get the third last business day of the delivery month.
MutableDateTime expiryDate = new MutableDateTime(date.dayOfMonth().withMaximumValue());
expiryDate.setMillisOfDay(0);
int d = 3;
while (d > 1) {
if (isBusinessDay(expiryDate)) {
d--;
}
expiryDate.addDays(-1);
}
if (s != null && expiryDate.equals(s.getExpiry())) {
return s;
}
return new Symbol("GC", "NYMEX", "USD", expiryDate.toDateTime(), 100, 0.1);
}
public static Symbol getCLFutureSymbol(DateTime date) {
return getCLFutureSymbol(null, date);
}
public static Symbol getCLFutureSymbol(Symbol s, DateTime date) {
// Trading in the current delivery month shall cease on the third
// business
// day prior to the twenty-fifth calendar day of the
// month preceding the delivery month.
// If the twenty-fifth calendar day of the month is a non-business day,
// trading shall cease on the third business day prior
// to the last business day preceding the twenty-fifth calendar day.
// In the event that the official Exchange holiday schedule changes
// subsequent to the listing of a Crude Oil futures,
// the originally listed expiration date shall remain in effect. In the
// event that the originally listed expiration day is declared a
// holiday,
// expiration will move to the business day immediately prior.
MutableDateTime expiryDate = new MutableDateTime(date);
expiryDate.setMillisOfDay(0);
if (expiryDate.getDayOfMonth() > 25) {
expiryDate.addMonths(1);
}
expiryDate.setDayOfMonth(25);
while (!isBusinessDay(expiryDate)) {
expiryDate.addDays(-1);
}
int d = 3;
while (d > 0) {
if (isBusinessDay(expiryDate)) {
d--;
}
expiryDate.addDays(-1);
}
if (s != null && expiryDate.equals(s.getExpiry())) {
return s;
}
return new Symbol("CL", "NYMEX", "USD", expiryDate.toDateTime(), 1000, 0.01);
}
public static Symbol getONEFutureSymbol(DateTime date) {
return getONEFutureSymbol(null, date);
}
public static Symbol getONEFutureSymbol(Symbol s, DateTime date) {
DateTime expiryDate = getMostLiquidQuarterlyExpiry(date, 8);
if (s != null && expiryDate.equals(s.getExpiry())) {
return s;
}
return new Symbol(s.getCode(), "ONE", "USD", expiryDate, 100, 0.01);
}
public static DateTime getMostLiquidQuarterlyExpiry() {
return getMostLiquidQuarterlyExpiry(new DateTime(), 8);
}
public static DateTime getMostLiquidQuarterlyExpiry(DateTime date, int daysBeforeExpiry) {
DateTime expiryDate = getQuarterlyExpiryDate(date);
// Volume shifts to next month about x days before expiry
DateTime volumeShiftDate = expiryDate.minusDays(daysBeforeExpiry);
if (date.isBefore(volumeShiftDate)) {
return expiryDate;
}
return getQuarterlyExpiryDate(new DateTime(date.getMonthOfYear() == DateTimeConstants.DECEMBER ? date.getYear() + 1 : date.getYear(),
(date.getMonthOfYear() + 1) % 12, 1, 0, 0, 0, 0));
}
public static DateTime getMostLiquidOMXMonthlyExpiry(DateTime date) {
if (date == null) {
date = new DateTime();
} else if (date.isBefore(new DateTime(2008, 4, 17, 0, 0, 0, 0))) {
return getMostLiquidMonthlyExpiry(date, 8, 4);
}
return getMostLiquidMonthlyExpiry(date, 8, 3);
}
public static DateTime getMostLiquidVIXMonthlyExpiry(DateTime date) {
if (date == null) {
date = new DateTime();
}
DateTime expiryDate = getNthFriday(date.plusMonths(1), 3).minusDays(31);
DateTime volumeShiftDate = expiryDate.minusDays(2);
if (date.isBefore(volumeShiftDate)) {
return expiryDate;
}
return getNthFriday(date.plusMonths(2), 3).minusDays(31);
}
public static DateTime getMostLiquidMonthlyExpiry() {
return getMostLiquidMonthlyExpiry(new DateTime(), 7, 3);
}
public static DateTime getMostLiquidMonthlyExpiry(DateTime date, int daysBeforeExpiry, int nthFriday) {
DateTime expiryDate = getNthFriday(date, nthFriday);
// Volume shifts to next month about x days before expiry
DateTime volumeShiftDate = expiryDate.minusDays(daysBeforeExpiry);
if (date.isBefore(volumeShiftDate)) {
return expiryDate;
}
return getNthFriday(date.plusMonths(1), nthFriday);
}
public static DateTime getQuarterlyExpiryDate(DateTime date) {
// Get third Friday
MutableDateTime expiryDate = new MutableDateTime(date);
expiryDate.setMillisOfDay(0);
switch (expiryDate.getMonthOfYear()) {
case DateTimeConstants.JANUARY:
case DateTimeConstants.FEBRUARY:
case DateTimeConstants.MARCH:
expiryDate.setMonthOfYear(DateTimeConstants.MARCH);
break;
case DateTimeConstants.APRIL:
case DateTimeConstants.MAY:
case DateTimeConstants.JUNE:
expiryDate.setMonthOfYear(DateTimeConstants.JUNE);
break;
case DateTimeConstants.JULY:
case DateTimeConstants.AUGUST:
case DateTimeConstants.SEPTEMBER:
expiryDate.setMonthOfYear(DateTimeConstants.SEPTEMBER);
break;
case DateTimeConstants.OCTOBER:
case DateTimeConstants.NOVEMBER:
case DateTimeConstants.DECEMBER:
expiryDate.setMonthOfYear(DateTimeConstants.DECEMBER);
break;
}
expiryDate.setDayOfMonth(1);
if (expiryDate.getDayOfWeek() > DateTimeConstants.FRIDAY) {
expiryDate.addWeeks(3);
expiryDate.setDayOfWeek(DateTimeConstants.FRIDAY);
} else {
expiryDate.addWeeks(2);
expiryDate.setDayOfWeek(DateTimeConstants.FRIDAY);
}
return expiryDate.toDateTime();
}
private static DateTime getNthFriday(DateTime date, int nthFriday) {
MutableDateTime expiryDate = new MutableDateTime(date);
expiryDate.setMillisOfDay(0);
expiryDate.setDayOfMonth(1);
if (expiryDate.getDayOfWeek() > DateTimeConstants.FRIDAY) {
expiryDate.addWeeks(nthFriday);
expiryDate.setDayOfWeek(DateTimeConstants.FRIDAY);
} else {
expiryDate.addWeeks(nthFriday - 1);
expiryDate.setDayOfWeek(DateTimeConstants.FRIDAY);
}
return expiryDate.toDateTime();
}
private static boolean isBusinessDay(ReadableDateTime date) {
int dayOfWeek = date.getDayOfWeek();
if (dayOfWeek == DateTimeConstants.SATURDAY || dayOfWeek == DateTimeConstants.SUNDAY) {
return false;
}
return true;
}
}