/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.financial.aggregation;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.threeten.bp.LocalDate;
import com.opengamma.core.historicaltimeseries.HistoricalTimeSeriesSource;
import com.opengamma.core.position.Position;
import com.opengamma.core.position.impl.SimplePositionComparator;
import com.opengamma.core.security.Security;
import com.opengamma.core.security.SecuritySource;
import com.opengamma.id.UniqueId;
import com.opengamma.util.CompareUtils;
import com.opengamma.util.tuple.Pair;
/**
* Function to classify positions by Currency.
*
*/
public class LiquidityAggregationFunction implements AggregationFunction<String> {
private static final double LIQUIDATE_FACTOR = 0.1;
private boolean _useAttributes;
private static final String MORE_THAN_10_0 = "10+";
private static final String FROM_3_0_TO_10_0 = "3 - 10";
private static final String FROM_1_0_TO_3_0 = "1 - 3";
private static final String FROM_0_5_TO_1_0 = "0.5 - 1";
private static final String FROM_0_2_TO_0_5 = "0.2 - 0.5";
private static final String LESS_THAN_0_2 = "< 0.2";
private static final String NAME = "Liquidity";
private static final String FIELD = "VOLUME";
private static final String RESOLUTION_KEY = "DEFAULT_TSS_CONFIG";
private static final String NO_LIQUIDITY = "N/A";
private static final List<String> REQUIRED = Arrays.asList(MORE_THAN_10_0, FROM_3_0_TO_10_0, FROM_1_0_TO_3_0, FROM_0_5_TO_1_0, FROM_0_2_TO_0_5, LESS_THAN_0_2, NO_LIQUIDITY);
private HistoricalTimeSeriesSource _htsSource;
private SecuritySource _secSource;
private final boolean _caching = true;
private Map<UniqueId, Double> _daysToLiquidateCache = new HashMap<UniqueId, Double>();
private final Comparator<Position> _comparator = new SimplePositionComparator();
public LiquidityAggregationFunction(SecuritySource secSource, HistoricalTimeSeriesSource htsSource) {
this(secSource, htsSource, false);
}
public LiquidityAggregationFunction(SecuritySource secSource, HistoricalTimeSeriesSource htsSource, boolean useAttributes) {
_secSource = secSource;
_htsSource = htsSource;
_useAttributes = useAttributes;
}
@Override
public String classifyPosition(Position position) {
if (_useAttributes) {
Map<String, String> attributes = position.getAttributes();
if (attributes.containsKey(getName())) {
return attributes.get(getName());
} else {
return NO_LIQUIDITY;
}
} else {
try {
Security sec = position.getSecurityLink().getTarget();
if (sec == null) {
sec = position.getSecurityLink().resolve(_secSource); // side effect is it updates target.
}
Double daysToLiquidate = getDaysToLiquidate(position);
if (daysToLiquidate != null) {
return classifyLiquidity(daysToLiquidate);
} else {
return NO_LIQUIDITY;
}
} catch (UnsupportedOperationException ex) {
return NO_LIQUIDITY;
}
}
}
private Double getDaysToLiquidate(Position position) {
Security security = position.getSecurity();
UniqueId cacheKey = position.getUniqueId();
if (_caching && cacheKey != null) {
if (_daysToLiquidateCache.containsKey(cacheKey)) {
return _daysToLiquidateCache.get(cacheKey);
}
}
Pair<LocalDate, Double> latestDataPoint = _htsSource.getLatestDataPoint(FIELD, security.getExternalIdBundle(), RESOLUTION_KEY);
if (latestDataPoint != null) {
double volume = latestDataPoint.getSecond();
double daysToLiquidate = (volume / position.getQuantity().doubleValue()) * LIQUIDATE_FACTOR;
if (_caching && cacheKey != null) {
_daysToLiquidateCache.put(cacheKey, daysToLiquidate);
}
return daysToLiquidate;
} else {
if (_caching && cacheKey != null) {
_daysToLiquidateCache.put(cacheKey, null);
}
return null;
}
}
private String classifyLiquidity(Double daysToLiquidate) {
if (daysToLiquidate != null) {
if (daysToLiquidate < 0.2) {
return LESS_THAN_0_2;
} else if (daysToLiquidate < 0.5) {
return FROM_0_2_TO_0_5;
} else if (daysToLiquidate < 1.0) {
return FROM_0_5_TO_1_0;
} else if (daysToLiquidate < 3) {
return FROM_1_0_TO_3_0;
} else if (daysToLiquidate < 10) {
return FROM_3_0_TO_10_0;
} else {
return MORE_THAN_10_0;
}
} else {
return NO_LIQUIDITY;
}
}
public String getName() {
return NAME;
}
@Override
public Collection<String> getRequiredEntries() {
return REQUIRED;
}
@Override
public int compare(String o1, String o2) {
return CompareUtils.compareByList(REQUIRED, o1, o2);
}
@Override
public Comparator<Position> getPositionComparator() {
return _comparator;
}
}