
com.ddfplus.service.definition.DefinitionServiceImpl Maven / Gradle / Ivy
package com.ddfplus.service.definition;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.squareup.okhttp.OkHttpClient;
import com.squareup.okhttp.Request;
import com.squareup.okhttp.Response;
public class DefinitionServiceImpl implements DefinitionService {
// Every 12 hours
private static final int DEFAULT_DEFINITION_REFRESH_INTERVAL_SEC = 60 * 60 * 12;
private static final int NEAREST_MONTH = 0;
private static final String BASE_URL = "http://extras.ddfplus.com/json/";
private static final String FUTURES_URL = BASE_URL + "/futures/?root=";
private static final String OPTIONS_URL = BASE_URL + "/options/?root=";
private static final String EXCHANGE_SYMBOLS_URL = BASE_URL + "/instruments?exchange=";
private static final Logger logger = LoggerFactory.getLogger("DefinitionService");
private final Map futureRoots = new ConcurrentHashMap();
private final Map optionsRoots = new ConcurrentHashMap();
// Exchange Code to symbols
private final Map> exchangeSymbols = new ConcurrentHashMap>();
// Symbol to exchange Code, assumes only listed on 1 exchange
private final Map symbolToExchange = new ConcurrentHashMap();
private final Gson gson;
private OkHttpClient httpClient;
private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
private long refreshIntervalSec = DEFAULT_DEFINITION_REFRESH_INTERVAL_SEC;
public DefinitionServiceImpl() {
httpClient = new OkHttpClient();
httpClient.setConnectTimeout(3, TimeUnit.SECONDS);
httpClient.setReadTimeout(20, TimeUnit.SECONDS);
gson = new GsonBuilder().create();
}
@Override
public void init(Long intervalSec) {
if (intervalSec != null) {
this.refreshIntervalSec = intervalSec;
}
/*
* Start a refresh thread
*/
logger.info("Scheduling a symbol refresh every " + refreshIntervalSec + " seconds.");
RefreshThread refreshThread = new RefreshThread();
scheduler.scheduleAtFixedRate(refreshThread, refreshIntervalSec, refreshIntervalSec, TimeUnit.SECONDS);
}
@Override
public String[] getAllFutureSymbols(String root) {
String[] futures = new String[0];
// Look up in cache first
FuturesRoot futureRoot = futureRoots.get(root);
if (futureRoot == null) {
futureRoot = buildFutureContractCache(root);
}
if (futureRoot != null) {
futures = futureRoot.getContractSymbols();
}
return futures;
}
@Override
public String getFuturesMonthSymbol(String root, int month) {
String ret = null;
// Look up in cache first
FuturesRoot futureRoot = futureRoots.get(root);
if (futureRoot == null) {
futureRoot = buildFutureContractCache(root);
}
if (futureRoot != null) {
if (month == NEAREST_MONTH) {
// nearest month
return futureRoot.getNearestContract().getSymbol();
}
return futureRoot.getSymbolByMonth(month);
}
return ret;
}
@Override
public String[] getAllOptionsSymbols(String root) {
String[] options = new String[0];
OptionsRoot optionsRoot = optionsRoots.get(root);
if (optionsRoot == null) {
optionsRoot = buildOptionsContractCache(root);
}
if (optionsRoot != null) {
options = optionsRoot.getAllStrikeSymbols();
}
return options;
}
@Override
public String[] getAllOptionsMonthYearSymbols(String root, String monthYear) {
String[] options = new String[0];
OptionsRoot optionsRoot = optionsRoots.get(root);
if (optionsRoot == null) {
optionsRoot = buildOptionsContractCache(root);
}
if (optionsRoot != null) {
options = optionsRoot.getMonthYearStrikeSymbols(monthYear);
}
return options;
}
@Override
public String[] getExchangeSymbols(String exchangeCode) {
return lookUpExchangeSymbols(exchangeCode, false);
}
private String[] lookUpExchangeSymbols(String exchangeCode, boolean refresh) {
// look in cache first
List symbols = exchangeSymbols.get(exchangeCode);
if (refresh || symbols == null || symbols.size() == 0) {
// Look up from web service
Request request = new Request.Builder().url(EXCHANGE_SYMBOLS_URL + exchangeCode).build();
Response response;
try {
response = httpClient.newCall(request).execute();
if (response.isSuccessful()) {
String json = response.body().string();
logger.debug("< {}", json);
Type listType = new TypeToken>() {
}.getType();
List defs = gson.fromJson(json, listType);
logger.info("Received {} symbols for exchange {}", defs.size(), exchangeCode);
// Store
symbols = new ArrayList();
for (InstrumentDefinition def : defs) {
symbols.add(def.getSymbol_ddf());
symbolToExchange.put(def.getSymbol_ddf(), exchangeCode);
}
exchangeSymbols.put(exchangeCode, symbols);
}
} catch (Exception e) {
logger.error("Could not obtain symbols for exchange: {} error: {}", exchangeCode, e.getMessage());
}
}
return symbols.toArray(new String[symbols.size()]);
}
@Override
public String getExchange(String symbol) {
return symbolToExchange.get(symbol);
}
private FuturesRoot buildFutureContractCache(String root) {
FuturesRoot futureRoot = null;
// Look up from web service
Request request = new Request.Builder().url(FUTURES_URL + root).build();
Response response;
try {
response = httpClient.newCall(request).execute();
if (response.isSuccessful()) {
String json = response.body().string();
if (logger.isDebugEnabled()) {
logger.debug("< " + json);
}
futureRoot = processFutureRoot(json, root);
}
} catch (Exception e) {
logger.error("Could not obtain futures definitions for: " + root + " error: " + e.getMessage());
}
return futureRoot;
}
FuturesRoot processFutureRoot(String json, String root) {
FuturesRoot futureRoot = null;
// A map is returned, so need collection type
Type collectionType = new TypeToken
© 2015 - 2025 Weber Informatics LLC | Privacy Policy