Skip to content

Commit

Permalink
Implement ConfigurationManager, update Kraken and ANX
Browse files Browse the repository at this point in the history
  • Loading branch information
rafalkrupinski committed Nov 15, 2014
1 parent 019ea58 commit cab2455
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 76 deletions.
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
package com.xeiam.xchange.anx.v2.service.polling;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

import si.mazi.rescu.SynchronizedValueFactory;

import com.xeiam.xchange.ExchangeSpecification;
import com.xeiam.xchange.anx.v2.ANXV2;
import com.xeiam.xchange.currency.CurrencyPair;
import com.xeiam.xchange.service.BaseExchangeService;
import com.xeiam.xchange.service.polling.BasePollingService;
Expand All @@ -23,6 +20,14 @@
*/
public class ANXBasePollingService extends BaseExchangeService implements BasePollingService {

protected static final String PREFIX = "anx";
protected static final String KEY_ORDER_SIZE_MIN_DEFAULT = PREFIX + SUF_ORDER_SIZE_MIN_DEFAULT;
protected static final String KEY_ORDER_SIZE_SCALE_DEFAULT = PREFIX + SUF_ORDER_SIZE_SCALE_DEFAULT ;
protected static final String PREKEY_ORDER_SIZE_MIN = PREFIX + IN_ORDER_SIZE_MIN;
protected static final String KEY_ORDER_PRICE_SCALE_DEFAULT = PREFIX + SUF_ORDER_PRICE_SCALE_DEFAULT;
protected static final String KEY_ORDER_FEE_POLICY_MAKER = PREFIX + ".order.feePolicy.maker";
protected static final String KEY_ORDER_FEE_DISCOUNT = PREFIX + ".order.fee.makerDiscount";

static final List<CurrencyPair> CURRENCY_PAIRS = Arrays.asList(

new CurrencyPair("BTC", "USD"),
Expand Down Expand Up @@ -141,8 +146,6 @@ public class ANXBasePollingService extends BaseExchangeService implements BasePo

private final SynchronizedValueFactory<Long> nonceFactory;

protected final Properties properties = new Properties();

/**
* Constructor
*
Expand All @@ -152,11 +155,6 @@ public ANXBasePollingService(ExchangeSpecification exchangeSpecification, Synchr

super(exchangeSpecification);
this.nonceFactory = nonceFactory;
try {
properties.load(ANXV2.class.getResourceAsStream("ANXV2.properties"));
} catch (IOException e) {
throw new IllegalStateException(e);
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@

import java.io.IOException;
import java.math.BigDecimal;
import java.util.Properties;

import static com.xeiam.xchange.utils.ConfigurationManager.CFG_MGR;

/**
* @author Rafał Krupiński
*/
public class ANXMarketMetadataService extends ANXBasePollingService implements MarketMetadataService {
private final ANXV2 anxV2;
private final ANXV2Digest signatureCreator;
private static final BigDecimal MAKER_DISCOUNT = new BigDecimal(".5");


public ANXMarketMetadataService(ExchangeSpecification exchangeSpecification, SynchronizedValueFactory<Long> nonceFactory) {

Expand All @@ -41,28 +42,30 @@ public ANXMarketMetadataService(ExchangeSpecification exchangeSpecification, Syn
@Override
public MarketMetadata getMarketMetadata(CurrencyPair pair) throws ExchangeException, NotAvailableFromExchangeException, NotYetImplementedForExchangeException, IOException {

int amountScale = getIntProperty(KEY_ORDER_SIZE_SCALE_DEFAULT);
Properties properties = CFG_MGR.getProperties();
int amountScale = getIntProperty(KEY_ORDER_SIZE_SCALE_DEFAULT, properties);
String amountMinimumStr = properties.getProperty(PREKEY_ORDER_SIZE_MIN + pair.baseSymbol);
if (amountMinimumStr == null)
properties.getProperty(KEY_ORDER_SIZE_MIN_DEFAULT);
BigDecimal amountMinimum = new BigDecimal(amountMinimumStr).setScale(amountScale);

int priceScale = getIntProperty(KEY_ORDER_PRICE_SCALE_DEFAULT);
int priceScale = getIntProperty(KEY_ORDER_PRICE_SCALE_DEFAULT, properties);

BigDecimal orderFee = getANXAccountInfo().getTradeFee().movePointLeft(2);
if(!getBoolProperty(KEY_ORDER_FEE_POLICY_MAKER)) {
orderFee = orderFee.multiply(MAKER_DISCOUNT);
if(!getBoolProperty(KEY_ORDER_FEE_POLICY_MAKER, properties)) {

orderFee = orderFee.multiply(new BigDecimal(properties.getProperty(KEY_ORDER_FEE_DISCOUNT)));
}

return new BaseMarketMetadata(amountMinimum, priceScale, orderFee);
}

protected int getIntProperty(String key) {
protected int getIntProperty(String key, Properties properties) {

return Integer.parseInt(properties.getProperty(key));
}

protected boolean getBoolProperty(String key){
protected boolean getBoolProperty(String key, Properties properties){

String str = properties.getProperty(key);
return str != null && Boolean.parseBoolean(str);
Expand Down

This file was deleted.

5 changes: 5 additions & 0 deletions xchange-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,10 @@
<artifactId>rescu</artifactId>
</dependency>

<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,10 @@
*/
public abstract class BaseExchangeService {

protected static final String KEY_ORDER_SIZE_MIN_DEFAULT = "order.size.min.default";
protected static final String KEY_ORDER_SIZE_SCALE_DEFAULT = "order.size.scale.default";
protected static final String PREKEY_ORDER_SIZE_MIN = "order.size.min.";
protected static final String KEY_ORDER_PRICE_SCALE_DEFAULT = "order.price.scale.default";
protected static final String KEY_ORDER_FEE_POLICY_MAKER = "order.fee-policy.maker";
protected static final String SUF_ORDER_SIZE_MIN_DEFAULT = ".order.size.min.default";
protected static final String SUF_ORDER_SIZE_SCALE_DEFAULT = ".order.size.scale.default";
protected static final String IN_ORDER_SIZE_MIN = ".order.size.min.";
protected static final String SUF_ORDER_PRICE_SCALE_DEFAULT = ".order.price.scale.default";

/**
* The exchange specification containing session-specific information
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,44 +8,112 @@
import java.net.URL;
import java.util.Properties;

import static org.apache.commons.io.IOUtils.closeQuietly;
import static org.apache.commons.io.IOUtils.copy;

public class ConfigurationManager {
final public static ConfigurationManager CFG_MGR = new ConfigurationManager();

final private static Logger log = LoggerFactory.getLogger(ConfigurationManager.class);

final private static String CFG_FILE_NAME = "xchange.properties";

final private static URL DEFAULT_REMOTE;

static {

try {
DEFAULT_REMOTE = new URL("https://github.com/timmolter/XChange/raw/develop/xchange-core/src/main/resources/configuration.properties");
DEFAULT_REMOTE = new URL("https://github.com/timmolter/XChange/raw/develop/xchange-core/src/main/resources/" + CFG_FILE_NAME);
} catch (MalformedURLException e) {
throw new ExceptionInInitializerError(e);
}
}

/**
* System property containing local override path for the configuration
*/
public static final String KEY_OVERRIDE_PATH = "xchange.config.override";

/**
* System property containing local storage path for the configuration update file
*/
public static final String KEY_LOCAL_PATH = "xchange.config.local";

/**
* System property containing URL for the remote configuration
*/
public static final String KEY_REMOTE_URL = "xchange.config.remote";

private File override;

private File local;

private URL remote;

private Properties properties;

public void init() {
override = getFile("xchange.configuration.override", override, true);
/**
* If the override file is configured, either by a system property or programmatically, the properties
* are loaded from the file and exposed to the exchange clients.
*
* If not, but the remote update was configured, either by a system property or programmatically,
* remote configuration is downloaded, stored locally and used to load the configuration.
*
* If not, the internal configuration file, kept in xchange-core, is used.
*
* Exchange client implementation should never call this method directly.
*
* Note: downloading a file over the Internet may take significant amount of time.
*
* @return false if update was not configured
*/
public boolean update() throws IOException {
override = getFile(KEY_OVERRIDE_PATH, override, true);

if (override != null) {
log.debug("Override file: {}; updating disabled");
init(override);
return;
return false;
}

local = getFile("xchange.configuration.local", local, false);
local = getFile(KEY_LOCAL_PATH, local, false);
if (local != null) {
remote = getRemote("xchange.configuration.remote", remote);
update();
remote = getRemote(KEY_REMOTE_URL, remote);
updateRemote();
init(local);
return true;
} else {
initInternal();
return false;
}
}

/**
* Returns the current configuration properties. May never return null.
*
* @return the current configuration properties. Never a null.
*/
public Properties getProperties() {
if (properties == null) {
try {
update();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return properties;
}

private void updateRemote() throws IOException {
InputStream input = null;
OutputStream output = null;
try {
input = remote.openStream();
output = new FileOutputStream(local);
copy(input, output);
} finally {
closeQuietly(input);
closeQuietly(output);
}
}

Expand Down Expand Up @@ -75,28 +143,25 @@ private static File getFile(String propertyKey, File defaultFile, boolean requir
}
}

public void update() {
}

private void initInternal() throws IOException {

InputStream input = getClass().getClassLoader().getResourceAsStream("configuration.properties");
if (input == null)
throw new IllegalStateException("Configuration resource not found");

InputStream input = null;
try {
input = getClass().getClassLoader().getResourceAsStream(CFG_FILE_NAME);
if (input == null)
throw new IllegalStateException("Configuration resource not found");
init(input);
} finally {
input.close();
closeQuietly(input);
}
}

private void init(File file) throws IOException {
InputStream input = new FileInputStream(file);
InputStream input = null;
try {
input = new FileInputStream(file);
init(input);
} finally {
input.close();
closeQuietly(input);
}
}

Expand All @@ -117,16 +182,4 @@ public void setLocal(File local) {
public void setRemote(URL remote) {
this.remote = remote;
}

/**
* Returns the current configuration properties. May never return null.
*
* @return the current configuration properties. Never a null.
*/
public Properties getProperties() {
if (properties == null) {
init();
}
return properties;
}
}
25 changes: 25 additions & 0 deletions xchange-core/src/main/resources/xchange.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Exchange-specific configuration; data that is missing from the APIs, e.g. minimum trade and scale, price scale, and so on.
#
# Please keep exchanges in alphabetical order for easier navigation

# ANX
anx.order.size.min.BTC=.01
anx.order.size.min.LTC=.1
anx.order.size.min.DOGE=10000
anx.order.size.min.default=1
anx.order.size.scale.default=8

anx.order.price.scale.default=5

anx.order.fee.makerDiscount=.5

# user setting
# set to true if client code always makes limit orders to configure metadata service to return discounted fee factor
anx.order.feePolicy.maker=false


# Kraken
kraken.order.size.min.default=.01


#...
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;

import si.mazi.rescu.ParamsDigest;
Expand All @@ -30,14 +29,16 @@

public class KrakenBasePollingService<T extends Kraken> extends BaseExchangeService implements BasePollingService {

protected static final String PREFIX = "kraken";
protected static final String KEY_ORDER_SIZE_MIN_DEFAULT = PREFIX + SUF_ORDER_SIZE_MIN_DEFAULT;

private final Set<CurrencyPair> CURRENCY_PAIRS = new HashSet<CurrencyPair>();
private final Set<String> FIAT_CURRENCIES = new HashSet<String>();
private final Set<String> DIGITAL_CURRENCIES = new HashSet<String>();

protected T kraken;
protected ParamsDigest signatureCreator;
protected SynchronizedValueFactory<Long> nonce;
protected final Properties properties = new Properties();

/**
* Constructor
Expand All @@ -48,12 +49,6 @@ public KrakenBasePollingService(Class<T> type, ExchangeSpecification exchangeSpe

super(exchangeSpecification);

try {
properties.load(Kraken.class.getResourceAsStream("Kraken.properties"));
} catch (IOException e) {
throw new IllegalStateException(e);
}

kraken = RestProxyFactory.createProxy(type, exchangeSpecification.getSslUri());
signatureCreator = KrakenDigest.createInstance(exchangeSpecification.getSecretKey());
nonce = nonceFactory;
Expand Down
Loading

0 comments on commit cab2455

Please sign in to comment.