package nl.komtek.gpi.controllers; import com.cf.data.map.poloniex.PoloniexDataMapper; import com.cf.data.model.poloniex.PoloniexChartData; import com.cf.data.model.poloniex.PoloniexCompleteBalance; import com.cf.data.model.poloniex.PoloniexTradeHistory; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import nl.komtek.gpi.services.GunbotProxyService; import nl.komtek.gpi.utils.Util; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.util.StringUtils; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.math.BigDecimal; import java.time.ZoneOffset; import java.util.Arrays; import java.util.Calendar; import java.util.Iterator; import java.util.List; import java.util.Map; /** * Created by Elroy on 17-6-2017. */ @Controller public class GunbotProxyController { @Autowired private GunbotProxyService gunbotProxyService; @Value("${doubleBuyProtection:false}") private boolean doubleBuyProtection; @Value("${doubleBuyProtectionSeconds:0}") private int doubleBuyProtectionSeconds; @Autowired private Util util; private Logger logger = LogManager.getLogger(GunbotProxyController.class); private PoloniexDataMapper mapper = new PoloniexDataMapper(); @RequestMapping(value = "/public/**") @ResponseBody public String interceptAllCalls(HttpServletRequest request) { logger.info("intercepted -- " + request.getRequestURL() + "?" + request.getQueryString() + "?command=" + request.getParameter("command")); return "intercepted"; } @RequestMapping(value = "/tradingApi/**") @ResponseBody public String tradingRequests(HttpServletRequest request) { logger.debug(request.getRequestURL() + "??command=" + request.getParameter("command")); request.getParameterMap().keySet().forEach((e) -> System.out.print(e + "-")); return "trading api intercepted"; } @RequestMapping(value = "/public/**", params = "command=returnOrderBook") @ResponseBody public String publicRequestOrderBook(@RequestParam String currencyPair) { return gunbotProxyService.getOrderBook(currencyPair); } @RequestMapping(value = "/public/**", params = "command=return24hVolume") @ResponseBody public String publicRequest24hVolume() { return gunbotProxyService.get24hVolume(); } @RequestMapping(value = "/public/**", params = "command=returnTradeHistory") @ResponseBody public String publicRequestTradeHistory(@RequestParam String currencyPair, @RequestParam(required = false) String start, @RequestParam(required = false) String end) { final long startLong; if (start.indexOf(".") > 0) { startLong = Long.valueOf(start.substring(0, start.indexOf("."))); } else { startLong = Long.valueOf(start); } final long endLong; if (end == null) { Calendar cal = Calendar.getInstance(); endLong = cal.getTimeInMillis() / 1000; } else if (end.indexOf(".") > 0) { endLong = Long.valueOf(end.substring(0, end.indexOf("."))); } else { endLong = Long.valueOf(end); } return gunbotProxyService.getPublicTradeHistory(currencyPair, startLong, endLong); } @RequestMapping(value = "/public/**", params = "command=returnChartData") @ResponseBody public String publicRequestChartData(HttpServletRequest request, @RequestParam String currencyPair, @RequestParam String start, @RequestParam long period) throws InterruptedException { String result = gunbotProxyService.getChartData(currencyPair, period); return filterChartDataByDate(start, result); } @RequestMapping(value = "/public/**", params = "command=returnTicker") @ResponseBody public String publicRequestTicker() { return gunbotProxyService.getTicker(); } @RequestMapping(value = "/tradingApi/**", params = "command=returnCompleteBalances") @ResponseBody public String tradingRequestCompleteBalances(HttpServletRequest request) { String market = "default"; if (gunbotProxyService.isUsingMultipleMarkets()) { String key = request.getHeader("key"); market = gunbotProxyService.getMarket(key); } String result = gunbotProxyService.getCompleteBalances(market); result = hideDust(result); return result; } @RequestMapping(value = "/tradingApi/**", params = "command=returnOpenOrders") @ResponseBody public String tradingRequestOpenOrders(HttpServletRequest request, @RequestParam String currencyPair) { String market = "default"; if (gunbotProxyService.isUsingMultipleMarkets()) { String key = request.getHeader("key"); market = gunbotProxyService.getMarket(key); } String result = gunbotProxyService.getOpenOrders(market); JsonElement jElement = new JsonParser().parse(result); JsonObject jObject = jElement.getAsJsonObject(); JsonArray jArray = hideOpenOrders(jObject.getAsJsonArray(currencyPair)); return jArray != null ? jArray.toString() : "[]"; } @RequestMapping(value = "/tradingApi/**", params = "command=returnTradeHistory") @ResponseBody public String tradingRequestTradeHistory(HttpServletRequest request, @RequestParam String currencyPair, @RequestParam(required = false) String start) { String market = "default"; if (gunbotProxyService.isUsingMultipleMarkets()) { String key = request.getHeader("key"); market = gunbotProxyService.getMarket(key); } String result = gunbotProxyService.getTradeHistory(market); return filterTradeHistoryByDate(currencyPair, start, result); } @RequestMapping(value = "/tradingApi/**", params = "command=cancelOrder") @ResponseBody public String tradingRequestCancelOrder(HttpServletRequest request, @RequestParam String orderNumber) { String key = request.getHeader("key"); return gunbotProxyService.cancelOrder(key, orderNumber); } @RequestMapping(value = "/tradingApi/**", params = "command=sell") @ResponseBody public String tradingRequestSell(HttpServletRequest request, @RequestParam String currencyPair, @RequestParam BigDecimal rate, @RequestParam BigDecimal amount) { String key = request.getHeader("key"); return gunbotProxyService.sellOrder(key, currencyPair, rate, amount); } @RequestMapping(value = "/tradingApi/**", params = "command=buy") @ResponseBody public String tradingRequestBuy(HttpServletRequest request, HttpServletResponse response, @RequestParam String currencyPair, @RequestParam BigDecimal rate, @RequestParam BigDecimal amount) throws IOException { boolean globalSellOnlyMode = Boolean.parseBoolean(util.getConfigurationProperty("sellOnlyMode")); boolean pairSellOnlyMode = Boolean.parseBoolean(util.getConfigurationProperty(String.format("%s_sellOnlyMode", currencyPair))); if (globalSellOnlyMode || pairSellOnlyMode) { JsonObject jsonObject = new JsonObject(); String message = String.format("You are not allowed to buy. Sell Only mode is active for %s", currencyPair); jsonObject.addProperty("error", message); logger.info(jsonObject.toString()); return jsonObject.toString(); } String key = request.getHeader("key"); if (doubleBuyProtection || doubleBuyProtectionSeconds > 0) { return gunbotProxyService.buyOrderWithProtection(key, currencyPair, rate, amount); } else { return gunbotProxyService.buyOrder(key, currencyPair, rate, amount); } } private String filterTradeHistoryByDate(String currency, String start, String result) { final long startLong; if (start.indexOf(".") > 0) { startLong = Long.valueOf(start.substring(0, start.indexOf("."))); } else { startLong = Long.valueOf(start); } if (result.equals("[]")) { return result; } JsonParser jsonParser = new JsonParser(); JsonElement jElement = jsonParser.parse(result); JsonObject jObject = jElement.getAsJsonObject(); JsonObject filteredjObject = new JsonObject(); for (Map.Entry entry : jObject.entrySet()) { if (!currency.equalsIgnoreCase("all") && !currency.equalsIgnoreCase(entry.getKey().toString())) { continue; } List<PoloniexTradeHistory> tradeHistory = mapper.mapTradeHistory(entry.getValue().toString()); JsonArray filteredjArray = new JsonArray(); tradeHistory.stream() .filter(e -> e.date.toEpochSecond(ZoneOffset.UTC) >= startLong) .map(e -> jsonParser.parse(e.toString())) .forEach(filteredjArray::add); filteredjObject.add(entry.getKey().toString(), filteredjArray); } if (currency.equals("all")) { return (filteredjObject.entrySet().size() == 0) ? "[]" : filteredjObject.toString(); } else { return (filteredjObject.entrySet().size() == 0) ? "[]" : filteredjObject.getAsJsonArray(currency).toString(); } } private String filterChartDataByDate(String start, String result) { final long startLong; if (start.indexOf(".") > 0) { startLong = Long.valueOf(start.substring(0, start.indexOf("."))); } else { startLong = Long.valueOf(start); } if (result.equals("[]")) { return result; } if (result.contains("error")) { return result; } List<PoloniexChartData> chartData = mapper.mapChartData(result); JsonParser jsonParser = new JsonParser(); JsonArray filteredjArray = new JsonArray(); chartData.stream() .filter(e -> e.date >= startLong) .map(e -> jsonParser.parse(e.toString())) .forEach(filteredjArray::add); return filteredjArray.toString(); } private JsonArray hideOpenOrders(JsonArray jsonArray) { for (Iterator<JsonElement> it = jsonArray.iterator(); it.hasNext(); ) { JsonElement element = it.next(); JsonObject jsonObject = element.getAsJsonObject(); String orderNumber = jsonObject.get("orderNumber").getAsString(); String[] orderNumbersToHide = StringUtils.trimAllWhitespace(util.getConfigurationProperty("hideOrders", "")).split(","); if (Arrays.asList(orderNumbersToHide).contains(orderNumber)) { it.remove(); } } return jsonArray; } private String hideDust(String result) { boolean hidedust = Boolean.parseBoolean(util.getConfigurationProperty("hideDust")); if (!hidedust) { return result; } JsonParser jsonParser = new JsonParser(); JsonElement jElement = jsonParser.parse(result); JsonObject jObject = jElement.getAsJsonObject(); JsonObject filteredObject = new JsonObject(); for (Map.Entry entry : jObject.entrySet()) { JsonElement element = (JsonElement) entry.getValue(); BigDecimal available = BigDecimal.valueOf(element.getAsJsonObject().get("available").getAsDouble()); BigDecimal onOrders = BigDecimal.valueOf(element.getAsJsonObject().get("onOrders").getAsDouble()); BigDecimal btcValue = BigDecimal.valueOf(element.getAsJsonObject().get("btcValue").getAsDouble()); if (available.doubleValue() == 0) { filteredObject.add(entry.getKey().toString(), element); } double approximatePrice = btcValue.doubleValue() / available.add(onOrders).doubleValue(); double availableValue = available.doubleValue() * approximatePrice; if (availableValue < 0.00015) { available = BigDecimal.ZERO; } PoloniexCompleteBalance balance = new PoloniexCompleteBalance(available, onOrders, btcValue); filteredObject.add(entry.getKey().toString(), jsonParser.parse(balance.toString())); } return filteredObject.toString(); } }