Added support fot Bitfinex (withdrawal is not supported by bitfinex)

This commit is contained in:
b00lean 2014-11-02 20:53:52 +01:00
parent 35e54b31cb
commit c1a41a1427
6 changed files with 281 additions and 2 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.git
.DS_Store
dist/
bin/
build/

View File

@ -24,10 +24,19 @@
<param name="price" />
<cryptocurrency>BTC</cryptocurrency>
</ratesource>
<ratesource prefix="bitfinex" name ="Bitfinex.com Exchange" >
<cryptocurrency>BTC</cryptocurrency>
</ratesource>
<paymentprocessor prefix="bitcoinpay" name="BitcoinPay.com" >
<param name="apikey" />
<cryptocurrency>BTC</cryptocurrency>
</paymentprocessor>
<!-- Bitfinex extension by Orillia BVBA -->
<exchange prefix="bitfinex" name="Bitfinex.com Exchange">
<param name="apikey" />
<param name="apisecret" />
<cryptocurrency>BTC</cryptocurrency>
</exchange>
<cryptologo cryptocurrency="BTC" file="btc.png"/>
</extension>
<extension class="com.generalbytes.batm.server.extensions.extra.dogecoin.DogecoinExtension">

View File

@ -18,6 +18,7 @@
package com.generalbytes.batm.server.extensions.extra.bitcoin;
import com.generalbytes.batm.server.extensions.*;
import com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.bitfinex.BitfinexExchange;
import com.generalbytes.batm.server.extensions.extra.bitcoin.paymentprocessors.bitcoinpay.BitcoinPayPP;
import com.generalbytes.batm.server.extensions.extra.bitcoin.sources.BitcoinAverageRateSource;
import com.generalbytes.batm.server.extensions.extra.bitcoin.sources.FixPriceRateSource;
@ -35,8 +36,19 @@ public class BitcoinExtension implements IExtension{
}
@Override
public IExchange createExchange(String exchangeLogin) {
return null; //no BTC exchange available in open source version so far (Bitstamp is in built-in extension)
public IExchange createExchange(String paramString) //(Bitstamp is in built-in extension)
{
if ((paramString != null) && (!paramString.trim().isEmpty()))
{
StringTokenizer paramTokenizer = new StringTokenizer(paramString, ":");
String prefix = paramTokenizer.nextToken();
if ("bitfinex".equalsIgnoreCase(prefix)) {
String apiKey = paramTokenizer.nextToken();
String apiSecret = paramTokenizer.nextToken();
return new BitfinexExchange(apiKey, apiSecret);
}
}
return null;
}
@Override
@ -118,6 +130,15 @@ public class BitcoinExtension implements IExtension{
}
}
return new FixPriceRateSource(rate);
}else if ("bitfinex".equalsIgnoreCase(exchangeType)) {
BigDecimal rate = BigDecimal.ZERO;
if (st.hasMoreTokens()) {
try {
rate = new BigDecimal(st.nextToken());
} catch (Throwable e) {
}
}
return new BitfinexExchange("**","**");
}
}
return null;

View File

@ -0,0 +1,244 @@
/*************************************************************************************
* Copyright (C) 2014 GENERAL BYTES s.r.o. All rights reserved.
*
* This software may be distributed and modified under the terms of the GNU
* General Public License version 2 (GPL2) as published by the Free Software
* Foundation and appearing in the file GPL2.TXT included in the packaging of
* this file. Please note that GPL2 Section 2[b] requires that all works based
* on this software must also be made publicly available under the terms of
* the GPL2 ("Copyleft").
*
* Contact information
* -------------------
*
* GENERAL BYTES s.r.o.
* Web : http://www.generalbytes.com
*
* Other information:
*
* This implementation was created in cooperation with Orillia BVBA
************************************************************************************/
package com.generalbytes.batm.server.extensions.extra.bitcoin.exchanges.bitfinex;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import com.generalbytes.batm.server.extensions.IRateSource;
import com.xeiam.xchange.dto.trade.LimitOrder;
import com.xeiam.xchange.dto.trade.OpenOrders;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.generalbytes.batm.server.extensions.ICurrencies;
import com.generalbytes.batm.server.extensions.IExchange;
import com.xeiam.xchange.Exchange;
import com.xeiam.xchange.ExchangeFactory;
import com.xeiam.xchange.ExchangeSpecification;
import com.xeiam.xchange.currency.CurrencyPair;
import com.xeiam.xchange.dto.Order.OrderType;
import com.xeiam.xchange.dto.marketdata.Ticker;
import com.xeiam.xchange.dto.trade.MarketOrder;
import com.xeiam.xchange.service.polling.PollingAccountService;
import com.xeiam.xchange.service.polling.PollingMarketDataService;
import com.xeiam.xchange.service.polling.PollingTradeService;
public class BitfinexExchange implements IExchange, IRateSource {
private static final Logger log = LoggerFactory.getLogger("batm.master.BitfinexEchange");
private Exchange exchange = null;
private String apiKey;
private String apiSecret;
private static HashMap<String,BigDecimal> rateAmounts = new HashMap<String, BigDecimal>();
private static HashMap<String,Long> rateTimes = new HashMap<String, Long>();
private static final long MAXIMUM_ALLOWED_TIME_OFFSET = 30 * 1000;
public BitfinexExchange(String apiKey, String apiSecret) {
this.apiKey = apiKey;
this.apiSecret = apiSecret;
}
private synchronized Exchange getExchange() {
if (this.exchange == null) {
ExchangeSpecification bfxSpec = new com.xeiam.xchange.bitfinex.v1.BitfinexExchange().getDefaultExchangeSpecification();
bfxSpec.setApiKey(this.apiKey);
bfxSpec.setSecretKey(this.apiSecret);
this.exchange = ExchangeFactory.INSTANCE.createExchange(bfxSpec);
}
return this.exchange;
}
public Set<String> getCryptoCurrencies() {
Set<String> cryptoCurrencies = new HashSet<String>();
cryptoCurrencies.add(ICurrencies.BTC);
return cryptoCurrencies;
}
public Set<String> getFiatCurrencies() {
Set<String> fiatCurrencies = new HashSet<String>();
fiatCurrencies.add(ICurrencies.USD);
return fiatCurrencies;
}
public String getPreferredFiatCurrency() {
return ICurrencies.USD;
}
@Override
public synchronized BigDecimal getExchangeRateLast(String cryptoCurrency, String fiatCurrency) {
String key = cryptoCurrency +"_" + fiatCurrency;
synchronized (rateAmounts) {
long now = System.currentTimeMillis();
BigDecimal amount = rateAmounts.get(key);
if (amount == null) {
BigDecimal result = getExchangeRateLastSync(cryptoCurrency, fiatCurrency);
log.debug("Called bitfinex exchange for rate: " + key + " = " + result);
rateAmounts.put(key,result);
rateTimes.put(key,now+MAXIMUM_ALLOWED_TIME_OFFSET);
return result;
}else {
Long expirationTime = rateTimes.get(key);
if (expirationTime > now) {
return rateAmounts.get(key);
}else{
//do the job;
BigDecimal result = getExchangeRateLastSync(cryptoCurrency, fiatCurrency);
log.debug("Called bitfinex exchange for rate: " + key + " = " + result);
rateAmounts.put(key,result);
rateTimes.put(key,now+MAXIMUM_ALLOWED_TIME_OFFSET);
return result;
}
}
}
}
private BigDecimal getExchangeRateLastSync(String cryptoCurrency, String cashCurrency) {
PollingMarketDataService marketDataService = getExchange().getPollingMarketDataService();
try {
Ticker ticker = marketDataService.getTicker(new CurrencyPair(cryptoCurrency,cashCurrency));
return ticker.getLast();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public BigDecimal getCryptoBalance(String cryptoCurrency) {
// [TODO] Can be extended to support LTC and DRK (and other currencies supported by BFX)
if (!ICurrencies.BTC.equalsIgnoreCase(cryptoCurrency)) {
return BigDecimal.ZERO;
}
log.debug("Calling Bitfinex exchange (getBalance)");
try {
return getExchange().getPollingAccountService().getAccountInfo().getBalance(cryptoCurrency);
} catch (IOException e) {
e.printStackTrace();
log.error("Bitfinex exchange (getBalance) failed with message: " + e.getMessage());
}
return null;
}
public BigDecimal getFiatBalance(String fiatCurrency) {
if (!ICurrencies.USD.equalsIgnoreCase(fiatCurrency)) {
return BigDecimal.ZERO;
}
log.debug("Calling Bitfinex exchange (getBalance)");
try {
return getExchange().getPollingAccountService().getAccountInfo().getBalance(fiatCurrency);
} catch (IOException e) {
e.printStackTrace();
log.error("Bitfinex exchange (getBalance) failed with message: " + e.getMessage());
}
return null;
}
public final String sendCoins(String destinationAddress, BigDecimal amount, String cryptoCurrency, String description) {
if (!ICurrencies.BTC.equalsIgnoreCase(cryptoCurrency)) {
log.error("Bitfinex supports only " + ICurrencies.BTC);
return null;
}
log.info("Calling bitfinex exchange (withdrawal destination: " + destinationAddress + " amount: " + amount + " " + cryptoCurrency + ")");
PollingAccountService accountService = getExchange().getPollingAccountService();
try {
accountService.withdrawFunds(destinationAddress, amount, destinationAddress);
} catch (IOException e) {
e.printStackTrace();
log.error("Bitfinex exchange (withdrawFunds) failed with message: " + e.getMessage());
}
return null;
}
public String purchaseCoins(BigDecimal amount, String cryptoCurrency, String fiatCurrencyToUse, String description) {
if (!ICurrencies.BTC.equalsIgnoreCase(cryptoCurrency)) {
log.error("Bitfinex implementation supports only " + ICurrencies.BTC);
return null;
}
if (!ICurrencies.USD.equalsIgnoreCase(fiatCurrencyToUse)) {
log.error("Bitfinex supports only " + ICurrencies.USD );
return null;
}
log.info("Calling Bitfinex exchange (purchase " + amount + " " + cryptoCurrency + ")");
PollingAccountService accountService = getExchange().getPollingAccountService();
PollingTradeService tradeService = getExchange().getPollingTradeService();
try {
log.debug("AccountInfo as String: " + accountService.getAccountInfo().toString());
CurrencyPair currencyPair = new CurrencyPair(cryptoCurrency, fiatCurrencyToUse);
MarketOrder order = new MarketOrder(OrderType.BID, amount, currencyPair);
log.debug("marketOrder = " + order);
String orderId = tradeService.placeMarketOrder(order);
log.debug("orderId = " + orderId + " " + order);
try {
Thread.sleep(2000); //give exchange 2 seconds to reflect open order in order book
} catch (InterruptedException e) {
e.printStackTrace();
}
// get open orders
log.debug("Open orders:");
boolean orderProcessed = false;
int numberOfChecks = 0;
while (!orderProcessed && numberOfChecks < 10) {
boolean orderFound = false;
OpenOrders openOrders = tradeService.getOpenOrders();
for (LimitOrder openOrder : openOrders.getOpenOrders()) {
log.debug("openOrder = " + openOrder);
if (orderId.equalsIgnoreCase(openOrder.getId())) {
orderFound = true;
}
}
if (orderFound) {
log.debug("Waiting for order to be processed.");
try {
Thread.sleep(3000); //don't get your ip address banned
} catch (InterruptedException e) {
e.printStackTrace();
}
}else{
orderProcessed = true;
}
numberOfChecks++;
}
if (orderProcessed) {
return orderId;
}
} catch (IOException e) {
e.printStackTrace();
log.error("Bitfinex exchange (purchaseCoins) failed with message: " + e.getMessage());
}
return null;
}
}