package jtrade;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
public class Symbol implements Comparable<Symbol> {
public enum SymbolType {
STOCK, FUTURE, INDEX, OPTION, CASH, CFD
}
public enum OptionRight {
CALL, PUT
}
protected String code;
protected String exchange;
protected String currency;
protected SymbolType type;
protected DateTime expiry;
protected OptionRight right;
protected double strike;
protected String fullCode;
protected int multiplier;
protected double minTick;
private int hash;
public Symbol(String code, String exchange, String currency, SymbolType type) {
this(code, exchange, currency, type, null, 1, 0.0, null, 0.01);
}
public Symbol(String code, String exchange, String currency, String type) {
this(code, exchange, currency, SymbolType.valueOf(type), null, 1, 0.0, null, 0.01);
}
public Symbol(String code, String exchange, String currency, String type, int multiplier, double minTick) {
this(code, exchange, currency, SymbolType.valueOf(type), null, multiplier, 0.0, null, minTick);
}
public Symbol(String code, String exchange, String currency, DateTime expiry, int multiplier, double minTick) {
this(code, exchange, currency, SymbolType.FUTURE, expiry, multiplier, 0.0, null, minTick);
}
public Symbol(String code, String exchange, String currency, SymbolType type, DateTime expiry, int multiplier, double strike, OptionRight right,
double minTick) {
this.code = code;
this.exchange = exchange;
this.currency = currency;
this.type = type;
this.expiry = expiry;
this.multiplier = multiplier;
this.strike = strike;
this.right = right;
this.minTick = minTick;
StringBuilder sb = new StringBuilder();
sb.append(code);
if (exchange != null) {
sb.append('-');
sb.append(exchange);
}
if (currency != null) {
sb.append('-');
sb.append(currency);
}
if (type != null) {
sb.append('-');
sb.append(type);
}
if (expiry != null) {
sb.append('-');
sb.append(expiry.toString("yyyyMMdd"));
}
if (strike > 0) {
sb.append('-');
sb.append(strike);
sb.append('-');
sb.append(right);
}
fullCode = sb.toString();
hash = fullCode.hashCode();
}
/**
* <code>-<exchange>-<currency>-<type>-<expiry>-<strike>-<right>
*
* e.g. ES-GLOBEX-USD-OPTION-201012-1080-CALL
*
* @parameter fullCode
*/
public Symbol(String fullCode) {
try {
this.multiplier = 1;
String[] parts = fullCode.split("-");
int i = 0;
int j = 0;
if (parts[1].equals(parts[2]) || parts[0].equals("TICK")) {
this.code = parts[i++].concat("-").concat(parts[i++]);
j++;
} else {
this.code = parts[i++];
}
this.exchange = parts[i++];
if (parts.length > 2 + j) {
this.currency = parts[i++];
}
if (parts.length > 3 + j) {
this.type = SymbolType.valueOf(parts[i++]);
}
if (parts.length > 4 + j) {
if (parts[4].length() <= 6) {
this.expiry = DateTimeFormat.forPattern("yyyyMM").parseDateTime(parts[4]);
} else {
this.expiry = DateTimeFormat.forPattern("yyyyMMdd").parseDateTime(parts[4]);
}
}
if (parts.length > 5 + j) {
this.strike = Double.parseDouble(parts[5]);
this.multiplier = 100; // We assume 100 for options
}
if (parts.length > 6 + j) {
this.right = OptionRight.valueOf(parts[6]);
}
if (SymbolType.OPTION.equals(type) && strike <= 0) {
throw new IllegalArgumentException("Symbol code does not contain strike: " + fullCode);
}
if (SymbolType.OPTION.equals(type) && right == null) {
throw new IllegalArgumentException("Symbol code does not contain right: " + fullCode);
}
this.fullCode = fullCode;
hash = fullCode.hashCode();
} catch (Exception e) {
throw new IllegalArgumentException("Cannot parse symbol code: " + fullCode, e);
}
}
public String getCode() {
return code;
}
public String getExchange() {
return exchange;
}
public String getCurrency() {
return currency;
}
public DateTime getExpiry() {
return expiry;
}
public int getMultiplier() {
return multiplier;
}
public double getStrike() {
return strike;
}
public SymbolType getType() {
return type;
}
public OptionRight getOptionRight() {
return right;
}
public double getMinTick() {
return minTick;
}
public boolean isUnknown() {
return type == null;
}
public boolean isStock() {
return type == SymbolType.STOCK;
}
public boolean isFuture() {
return type == SymbolType.FUTURE;
}
public boolean isIndex() {
return type == SymbolType.INDEX;
}
public boolean isOption() {
return type == SymbolType.OPTION;
}
public boolean isCash() {
return type == SymbolType.CASH;
}
public boolean isTickIndex() {
return type == SymbolType.INDEX && code.startsWith("TICK");
}
public String getFullCode() {
return fullCode;
}
@Override
public int hashCode() {
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Symbol)) {
return false;
}
Symbol other = (Symbol) obj;
if (hash != other.hash) {
return false;
}
return fullCode.equals(other.fullCode);
}
@Override
public String toString() {
return fullCode;
}
@Override
public int compareTo(Symbol other) {
int c = exchange.compareTo(other.exchange);
if (c != 0) {
return c;
}
return fullCode.compareTo(other.fullCode);
}
}