com.nubits.nubot.trading.TradeUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.nubits.nubot.trading.TradeUtils.java

Source

/*
 * Copyright (C) 2014 desrever <desrever at nubits.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 */
package com.nubits.nubot.trading;

/**
 *
 * @author desrever <desrever at nubits.com>
 */
import com.nubits.nubot.global.Constant;
import com.nubits.nubot.global.Global;
import com.nubits.nubot.models.ApiResponse;
import com.nubits.nubot.models.CurrencyPair;
import com.nubits.nubot.models.Order;
import com.nubits.nubot.utils.Utils;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
import java.util.TreeMap;
import java.util.logging.Logger;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

public class TradeUtils {

    private static final Logger LOG = Logger.getLogger(TradeUtils.class.getName());

    public static boolean tryCancelAllOrders(CurrencyPair pair) {
        boolean toRet = false;
        //get all orders
        ApiResponse activeOrdersResponse = Global.exchange.getTrade().getActiveOrders(Global.options.getPair());
        if (activeOrdersResponse.isPositive()) {
            ArrayList<Order> orderList = (ArrayList<Order>) activeOrdersResponse.getResponseObject();

            if (orderList.size() == 0) {
                toRet = true;
            } else {
                LOG.info("There are still : " + orderList.size() + " active orders");
                //Retry to cancel them to fix issue #14
                ApiResponse deleteOrdersResponse = Global.exchange.getTrade().clearOrders(pair);
                if (deleteOrdersResponse.isPositive()) {
                    boolean deleted = (boolean) deleteOrdersResponse.getResponseObject();

                    if (deleted) {
                        LOG.info("Order clear request succesfully");
                    } else {
                        toRet = false;
                        LOG.info("Could not submit request to clear orders");
                    }
                } else {
                    toRet = false;
                    LOG.severe(deleteOrdersResponse.getError().toString());
                }
            }
        } else {
            toRet = false;

            LOG.severe(activeOrdersResponse.getError().toString());
        }

        return toRet;
    }

    public static boolean takeDownOrders(String type, CurrencyPair pair) {
        boolean completed = true;
        //Get active orders
        ApiResponse activeOrdersResponse = Global.exchange.getTrade().getActiveOrders(Global.options.getPair());
        if (activeOrdersResponse.isPositive()) {
            ArrayList<Order> orderList = (ArrayList<Order>) activeOrdersResponse.getResponseObject();

            for (int i = 0; i < orderList.size(); i++) {
                Order tempOrder = orderList.get(i);
                if (tempOrder.getType().equalsIgnoreCase(type)) {
                    boolean tempDeleted = takeDownAndWait(tempOrder.getId(), 120 * 1000, pair);
                    if (!tempDeleted) {
                        completed = false;
                    }
                }
            }
        } else {
            LOG.severe(activeOrdersResponse.getError().toString());
            return false;
        }
        return completed;
    }

    public static boolean takeDownAndWait(String orderID, long timeoutMS, CurrencyPair pair) {

        ApiResponse deleteOrderResponse = Global.exchange.getTrade().cancelOrder(orderID, pair);
        if (deleteOrderResponse.isPositive()) {
            boolean delRequested = (boolean) deleteOrderResponse.getResponseObject();

            if (delRequested) {
                LOG.warning("Order " + orderID + " delete request submitted");
            } else {
                LOG.severe("Could not submit request to delete order" + orderID);
            }

        } else {
            LOG.severe(deleteOrderResponse.getError().toString());
        }

        //Wait until the order is deleted or timeout
        boolean timedout = false;
        boolean deleted = false;
        long wait = 6 * 1000;
        long count = 0L;
        do {
            try {
                Thread.sleep(wait);
                count += wait;
                timedout = count > timeoutMS;

                ApiResponse orderDetailResponse = Global.exchange.getTrade().isOrderActive(orderID);
                if (orderDetailResponse.isPositive()) {
                    deleted = !((boolean) orderDetailResponse.getResponseObject());
                    LOG.fine("Does order " + orderID + "  still exist?" + !deleted);
                } else {
                    LOG.severe(orderDetailResponse.getError().toString());
                    return false;
                }
            } catch (InterruptedException ex) {
                LOG.severe(ex.toString());
                return false;
            }
        } while (!deleted && !timedout);

        if (timedout) {
            return false;
        }
        return true;
    }

    public static double getSellPrice(double txFee) {
        if (Global.isDualSide) {
            return 1 + (0.01 * txFee);
        } else {
            return 1 + (0.01 * txFee) + Global.options.getPriceIncrement();
        }

    }

    public static double getBuyPrice(double txFeeUSDNTB) {
        return 1 - (0.01 * txFeeUSDNTB);
    }

    public static ArrayList<Order> filterOrders(ArrayList<Order> originalList, String type) {
        ArrayList<Order> toRet = new ArrayList<>();
        for (int i = 0; i < originalList.size(); i++) {
            Order temp = originalList.get(i);
            if (temp.getType().equalsIgnoreCase(type)) {
                toRet.add(temp);
            }
        }

        return toRet;
    }
    //Build the query string given a set of query parameters

    /**
     *
     * @param args
     * @param encoding
     * @return
     */
    public static String buildQueryString(HashMap<String, String> args, String encoding) {
        String result = new String();
        for (String hashkey : args.keySet()) {
            if (result.length() > 0) {
                result += '&';
            }
            try {
                result += URLEncoder.encode(hashkey, encoding) + "="
                        + URLEncoder.encode(args.get(hashkey), encoding);
            } catch (Exception ex) {
                LOG.severe(ex.toString());
            }
        }
        return result;
    }

    public static String buildQueryString(TreeMap<String, String> args, String encoding) {
        String result = new String();
        for (String hashkey : args.keySet()) {
            if (result.length() > 0) {
                result += '&';
            }
            try {
                result += URLEncoder.encode(hashkey, encoding) + "="
                        + URLEncoder.encode(args.get(hashkey), encoding);
            } catch (Exception ex) {
                LOG.severe(ex.toString());
            }
        }
        return result;
    }

    //The two methods below have been amalgamated into the CCDEK wrapper
    //TODO - get rid of these ccedk =methods once testing has taken place
    public static int offset = 0;

    public static String getCCDKEvalidNonce() {
        //It tries to send a wrong nonce, get the allowed window, and use it for the actual call
        String wrongNonce = "1234567891";
        String lastdigits;
        //LOG.info("Offset = " + Objects.toString(offset));
        String validNonce;
        if (offset == 0) {
            try {
                String htmlString = Utils.getHTML("https://www.ccedk.com/api/v1/currency/list?nonce=" + wrongNonce,
                        false);
                //LOG.info(htmlString);
                //LOG.info(Objects.toString(System.currentTimeMillis() / 1000L));
                validNonce = getCCDKEvalidNonce(htmlString);
                offset = Integer.parseInt(validNonce) - (int) (System.currentTimeMillis() / 1000L);
                //LOG.info("Offset = " + Objects.toString(offset));
            } catch (IOException io) {
                //LOG.info(io.toString());
                validNonce = "";
            }
        } else {
            validNonce = Objects.toString(((int) (System.currentTimeMillis() / 1000L) + offset) - 1);
        }
        if (!validNonce.equals("")) {
            lastdigits = validNonce.substring(validNonce.length() - 2);
            if (lastdigits.equals("98") || lastdigits.equals("99")) {
                offset = 0;
                validNonce = getCCDKEvalidNonce();
            }
        } else {
            offset = 0;
            validNonce = getCCDKEvalidNonce();
        }
        //LOG.info("Last digits = " + lastdigits + "\nvalidNonce = " + validNonce);
        return validNonce;
    }

    //used by ccedkqueryservice
    public static String getCCDKEvalidNonce(String htmlString) {

        JSONParser parser = new JSONParser();
        try {
            //{"errors":{"nonce":"incorrect range `nonce`=`1234567891`, must be from `1411036100` till `1411036141`"}
            JSONObject httpAnswerJson = (JSONObject) (parser.parse(htmlString));
            JSONObject errors = (JSONObject) httpAnswerJson.get("errors");
            String nonceError = (String) errors.get("nonce");

            //String startStr = " must be from";
            //int indexStart = nonceError.lastIndexOf(startStr) + startStr.length() + 2;
            //String from = nonceError.substring(indexStart, indexStart + 10);

            String startStr2 = " till";
            int indexStart2 = nonceError.lastIndexOf(startStr2) + startStr2.length() + 2;
            String to = nonceError.substring(indexStart2, indexStart2 + 10);

            //if (to.equals(from)) {
            //    LOG.info("Detected ! " + to + " = " + from);
            //    return "retry";
            //}

            return to;
        } catch (ParseException ex) {
            LOG.severe(htmlString + " " + ex.toString());
            return "1234567891";
        }
    }

    public static int getCCDKECurrencyId(String currencyCode) {
        /*
         * LAST UPDATED : 17 september
         * FROM : https://www.ccedk.com/api/v1/currency/list?nonce=1410950600
         * 1,LTC
         * 2,BTC
         * 3,USD
         * 4, EUR
         * 8,PPC
         * 15, NBT
            
         */
        final String BTC = Constant.BTC.getCode();
        String USD = Constant.USD.getCode();
        String PPC = Constant.PPC.getCode();

        int toRet = -1;

        switch (currencyCode) {
        case "BTC":
            toRet = 2;
            break;
        case "USD":
            toRet = 3;
            break;
        case "PPC":
            toRet = 8;
            break;
        case "LTC":
            toRet = 1;
            break;
        case "NBT":
            toRet = 15;
            break;
        case "EUR":
            toRet = 4;
            break;
        default:
            LOG.severe("Currency " + currencyCode + "not available");
            break;
        }
        return toRet;
    }

    public static int getCCDKECurrencyPairId(CurrencyPair pair) {
        /*
         * LAST UPDATED : 20 september
         FROM : https://www.ccedk.com/api/v1/pair/list?nonce=1410950600
         * 2 ,BTC USD
         * 14 , PPC USD
         * 13 , PPC BTC
         * 12 , PPC LTC
         * 47, NBT BTC
         * 48, NBT PPC
         * 46, NBT USD
         * 49, NBT EUR
         */

        int toRet = -1;

        if (pair.equals(Constant.BTC_USD)) {
            return 2;
        } else if (pair.equals(Constant.PPC_USD)) {
            return 14;
        } else if (pair.equals(Constant.PPC_BTC)) {
            return 13;
        } else if (pair.equals(Constant.PPC_LTC)) {
            return 12;
        } else if (pair.equals(Constant.NBT_BTC)) {
            return 47;
        } else if (pair.equals(Constant.NBT_PPC)) {
            return 48;
        } else if (pair.equals(Constant.NBT_USD)) {
            return 46;
        } else if (pair.equals(Constant.NBT_EUR)) {
            return 49;
        } else {
            LOG.severe("Pair " + pair.toString() + " not available");
        }

        return toRet;
    }

    public static CurrencyPair getCCEDKPairFromID(int id) {
        /*
         * LAST UPDATED : 20 september
         FROM : https://www.ccedk.com/api/v1/pair/list?nonce=1410950600
         * 2 ,BTC USD
         * 14 , PPC USD
         * 13 , PPC BTC
         * 12 , PPC LTC
         * 47, NBT BTC
         * 48, NBT PPC
         * 46, NBT USD
         * 49, NBT EUR
         */
        CurrencyPair toRet = new CurrencyPair(Constant.BTC, Constant.BTC);

        switch (id) {
        case 2:
            toRet = Constant.BTC_USD;
            break;
        case 12:
            toRet = Constant.PPC_LTC;
            break;
        case 13:
            toRet = Constant.PPC_BTC;
            break;
        case 14:
            toRet = Constant.PPC_USD;
            break;
        case 46:
            toRet = Constant.NBT_USD;
            break;
        case 47:
            toRet = Constant.NBT_BTC;
            break;
        case 48:
            toRet = Constant.NBT_PPC;
            break;
        case 49:
            toRet = Constant.NBT_EUR;
            break;
        default:
            LOG.severe("Pair with id = " + id + " not available");

        }
        return toRet;

    }

    public static String getCCEDKTickerUrl(CurrencyPair pair) {
        String nonce = TradeUtils.getCCDKEvalidNonce();
        return "https://www.ccedk.com/api/v1/stats/marketdepth?nonce=" + nonce + "&pair_id="
                + getCCDKECurrencyPairId(pair);
    }
}