Skip to content

Commit

Permalink
Prep for the 0.3-beta RC.
Browse files Browse the repository at this point in the history
Added PATCH for Kraken sending occasional 'EAPI:Invalid key' responses.
  • Loading branch information
gazbert committed Jul 31, 2016
1 parent a0041e1 commit edb1c28
Show file tree
Hide file tree
Showing 5 changed files with 92 additions and 16 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ and released under the [MIT license](http://opensource.org/licenses/MIT).
- Strategy API - Trading Strategies implement this for the Trading Engine to execute them.

Trading Strategies and Exchange Adapters are injected by the Trading Engine on startup. The bot uses a crude XML based
dependency injection framework to achieve this; the long term goal is for it to run as a [Spring Boot](http://projects.spring.io/spring-boot/)
app in a microservice system.
dependency injection framework to achieve this; the long term goal is to run it as a [Spring Boot](http://projects.spring.io/spring-boot/)
app in a [microservice](http://martinfowler.com/articles/microservices.html) system.

The bot was designed to fail hard and fast if any unexpected errors occur in the Exchange Adapters or Trading Strategies:
it will log the error, send an email alert (if configured), and then shutdown.
Expand Down Expand Up @@ -476,8 +476,8 @@ The following features are in the pipeline:

- Exchange Adapter for [Gemini](https://gemini.com/).
- REST API for configuring the bot.
- Admin app - a microservice for configuring and managing bots in the cloud.
- Web UI (written in [AngularJS](https://angularjs.org/)) for administering bots.
- Web UI (written in [AngularJS](https://angularjs.org/)) for configuring the bot.
- Admin app - a microservice for administering multiple bots in the cloud.
- Trade Analysis app - a microservice that will feed off trading events sent by the bots.
- Android app for administering bots.

Expand Down
Binary file modified config/samples/kraken/engine.xml
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
import java.util.*;

/**
* TODO 31 July 2016 - Contains PATCH for occasional 'EAPI:Invalid key' responses. Remove when I get to bottom of it!
* <p>
* Exchange Adapter for integrating with the Kraken exchange.
* The Kraken API is documented <a href="https://www.kraken.com/en-gb/help/api">here</a>.
Expand Down Expand Up @@ -380,9 +381,20 @@ public List<OpenOrder> getYourOpenOrders(String marketId) throws TradingApiExcep
return openOrders;

} else {
final String errorMsg = FAILED_TO_GET_OPEN_ORDERS + response;
LOG.error(errorMsg);
throw new TradingApiException(errorMsg);

/*
* TODO 31 July 2016 - PATCH for occasional 'EAPI:Invalid key' responses. Remove when I get to bottom of it!
*/
if (krakenResponse.error.contains("EAPI:Invalid key")) {
final String errorMsg = "Received another random Invalid API Key response - ignoring... " +
FAILED_TO_GET_OPEN_ORDERS + response;
LOG.error(errorMsg);
throw new ExchangeNetworkException(errorMsg);
} else {
final String errorMsg = FAILED_TO_GET_OPEN_ORDERS + response;
LOG.error(errorMsg);
throw new TradingApiException(errorMsg);
}
}

} else {
Expand Down Expand Up @@ -443,9 +455,20 @@ public String createOrder(String marketId, OrderType orderType, BigDecimal quant
return krakenAddOrderResult.txid.get(0);

} else {
final String errorMsg = FAILED_TO_ADD_ORDER + response;
LOG.error(errorMsg);
throw new TradingApiException(errorMsg);

/*
* TODO 31 July 2016 - PATCH for occasional 'EAPI:Invalid key' responses. Remove when I get to bottom of it!
*/
if (krakenResponse.error.contains("EAPI:Invalid key")) {
final String errorMsg = "Received another random Invalid API Key response - ignoring... " +
FAILED_TO_ADD_ORDER + response;
LOG.error(errorMsg);
throw new ExchangeNetworkException(errorMsg);
} else {
final String errorMsg = FAILED_TO_ADD_ORDER + response;
LOG.error(errorMsg);
throw new TradingApiException(errorMsg);
}
}

} else {
Expand Down Expand Up @@ -491,9 +514,20 @@ public boolean cancelOrder(String orderId, String marketIdNotNeeded) throws Trad
}

} else {
final String errorMsg = FAILED_TO_CANCEL_ORDER + response;
LOG.error(errorMsg);
throw new TradingApiException(errorMsg);

/*
* TODO 31 July 2016 - PATCH for occasional 'EAPI:Invalid key' responses. Remove when I get to bottom of it!
*/
if (krakenResponse.error.contains("EAPI:Invalid key")) {
final String errorMsg = "Received another random Invalid API Key response - ignoring... " +
FAILED_TO_CANCEL_ORDER + response;
LOG.error(errorMsg);
throw new ExchangeNetworkException(errorMsg);
} else {
final String errorMsg = FAILED_TO_CANCEL_ORDER + response;
LOG.error(errorMsg);
throw new TradingApiException(errorMsg);
}
}

} else {
Expand Down Expand Up @@ -587,9 +621,20 @@ public BalanceInfo getBalanceInfo() throws TradingApiException, ExchangeNetworkE
return new BalanceInfo(balancesAvailable, new HashMap<>());

} else {
final String errorMsg = FAILED_TO_GET_BALANCE + response;
LOG.error(errorMsg);
throw new TradingApiException(errorMsg);

/*
* TODO 31 July 2016 - PATCH for occasional 'EAPI:Invalid key' responses. Remove when I get to bottom of it!
*/
if (krakenResponse.error.contains("EAPI:Invalid key")) {
final String errorMsg = "Received another random Invalid API Key response - ignoring... " +
FAILED_TO_GET_BALANCE + response;
LOG.error(errorMsg);
throw new ExchangeNetworkException(errorMsg);
} else {
final String errorMsg = FAILED_TO_GET_BALANCE + response;
LOG.error(errorMsg);
throw new TradingApiException(errorMsg);
}
}

} else {
Expand Down
6 changes: 6 additions & 0 deletions src/test/exchange-data/kraken/AddOrder-apiKeyError.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"error": [
"EAPI:Invalid key"
],
"result": {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ public class TestKrakenExchangeAdapter {
private static final String ADD_ORDER_BUY_JSON_RESPONSE = "./src/test/exchange-data/kraken/AddOrder-buy.json";
private static final String ADD_ORDER_SELL_JSON_RESPONSE = "./src/test/exchange-data/kraken/AddOrder-sell.json";
private static final String ADD_ORDER_ERROR_JSON_RESPONSE = "./src/test/exchange-data/kraken/AddOrder-error.json";
private static final String ADD_ORDER_API_KEY_ERROR_JSON_RESPONSE = "./src/test/exchange-data/kraken/AddOrder-apiKeyError.json";
private static final String CANCEL_ORDER_JSON_RESPONSE = "./src/test/exchange-data/kraken/CancelOrder.json";
private static final String CANCEL_ORDER_ERROR_JSON_RESPONSE = "./src/test/exchange-data/kraken/CancelOrder-error.json";

Expand Down Expand Up @@ -450,6 +451,30 @@ public void testCreateOrderExchangeErrorResponse() throws Exception {
PowerMock.verifyAll();
}

/*
* TODO 31 July 2016 - Test for PATCH for occasional 'EAPI:Invalid key' responses. Remove when I get to bottom of it!
*/
@Test(expected = ExchangeNetworkException.class)
public void testCreateOrderExchangeApiKeyErrorResponse() throws Exception {

// Load the canned response from the exchange
final byte[] encoded = Files.readAllBytes(Paths.get(ADD_ORDER_API_KEY_ERROR_JSON_RESPONSE));
final AbstractExchangeAdapter.ExchangeHttpResponse exchangeResponse =
new AbstractExchangeAdapter.ExchangeHttpResponse(200, "OK", new String(encoded, StandardCharsets.UTF_8));

// Partial mock so we do not send stuff down the wire
final KrakenExchangeAdapter exchangeAdapter = PowerMock.createPartialMockAndInvokeDefaultConstructor(
KrakenExchangeAdapter.class, MOCKED_SEND_AUTHENTICATED_REQUEST_TO_EXCHANGE_METHOD);
PowerMock.expectPrivate(exchangeAdapter, MOCKED_SEND_AUTHENTICATED_REQUEST_TO_EXCHANGE_METHOD, eq(ADD_ORDER),
anyObject(Map.class)).andReturn(exchangeResponse);

PowerMock.replayAll();
exchangeAdapter.init(exchangeConfig);

exchangeAdapter.createOrder(MARKET_ID, OrderType.SELL, SELL_ORDER_QUANTITY, SELL_ORDER_PRICE);
PowerMock.verifyAll();
}

@Test(expected = ExchangeNetworkException.class)
public void testCreateOrderHandlesExchangeNetworkException() throws Exception {

Expand Down

0 comments on commit edb1c28

Please sign in to comment.