com.nubits.nubot.tasks.SubmitLiquidityinfoTask.java Source code

Java tutorial

Introduction

Here is the source code for com.nubits.nubot.tasks.SubmitLiquidityinfoTask.java

Source

/*
 * Copyright (C) 2015 Nu Development Team
 *
 * 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.tasks;

import com.nubits.nubot.RPC.NuRPCClient;
import com.nubits.nubot.bot.Global;
import com.nubits.nubot.bot.SessionManager;
import com.nubits.nubot.global.Constant;
import com.nubits.nubot.global.Settings;
import com.nubits.nubot.models.Amount;
import com.nubits.nubot.models.ApiResponse;
import com.nubits.nubot.models.Order;
import com.nubits.nubot.models.PairBalance;
import com.nubits.nubot.utils.FilesystemUtils;
import com.nubits.nubot.utils.Utils;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.TimerTask;

/**
 * Submit info via NuWalletRPC
 */
public class SubmitLiquidityinfoTask extends TimerTask {

    private static final Logger LOG = LoggerFactory.getLogger(SubmitLiquidityinfoTask.class.getName());
    private boolean verbose;

    private boolean wallsBeingShifted = false;
    private boolean firstOrdersPlaced = false;
    private boolean firstExecution = true;

    private String outputFile_orders;
    private String jsonFile_orders;
    private String jsonFile_balances;

    public SubmitLiquidityinfoTask(boolean verbose) {
        this.verbose = verbose;
    }

    private void initFiles() {
        if (SessionManager.sessionInterrupted())
            return; //external interruption

        this.outputFile_orders = Global.sessionLogFolder + "/" + Settings.ORDERS_FILENAME + ".csv";
        this.jsonFile_orders = Global.sessionLogFolder + "/" + Settings.ORDERS_FILENAME + ".json";
        this.jsonFile_balances = Global.sessionLogFolder + "/" + Settings.BALANCES_FILEAME + ".json";

        //create json file if it doesn't already exist
        LOG.debug("init files");
        File jsonF1 = new File(this.jsonFile_orders);
        if (!jsonF1.exists()) {
            try {
                jsonF1.createNewFile();
                LOG.debug("created " + jsonF1);
            } catch (Exception e) {
                LOG.error("error creating file " + jsonF1 + " " + e);
            }

            JSONObject history = new JSONObject();
            JSONArray orders = new JSONArray();
            history.put("orders", orders);
            FilesystemUtils.writeToFile(history.toJSONString(), this.jsonFile_orders, true);
        }
        if (SessionManager.sessionInterrupted())
            return; //external interruption

        //create json file if it doesn't already exist
        File jsonF2 = new File(this.jsonFile_balances);
        if (!jsonF2.exists()) {
            try {
                jsonF2.createNewFile();
                LOG.debug("created " + jsonF2);
            } catch (Exception e) {
                LOG.error("error creating file " + jsonF1 + " " + e);
            }

            JSONObject history = new JSONObject();
            JSONArray balances = new JSONArray();
            history.put("balances", balances);
            FilesystemUtils.writeToFile(history.toJSONString(), this.jsonFile_balances, true);
        }

        if (SessionManager.sessionInterrupted())
            return; //external interruption

        File of = new File(this.outputFile_orders);
        if (!of.exists()) {
            try {
                of.createNewFile();
                LOG.debug("created " + of);
            } catch (Exception e) {
                LOG.error("error creating file " + of + "  " + e);
            }
        }

        FilesystemUtils.writeToFile("timestamp,activeOrders, sells,buys, digest\n", this.outputFile_orders, false);

    }

    @Override
    public void run() {

        if (SessionManager.sessionInterrupted())
            return; //external interruption

        LOG.debug("Executing " + this.getClass());

        if (firstExecution) {
            initFiles();
            firstExecution = false;
        }
        checkOrders();

    }

    private void checkOrders() {

        if (SessionManager.sessionInterrupted())
            return; //external interruption

        if (!isWallsBeingShifted()) { //Do not report liquidity info during wall shifts (issue #23)
            if (isFirstOrdersPlaced()) {
                String response1 = reportTier1(); //active orders

                if (SessionManager.sessionInterrupted())
                    return; //external interruption

                String response2 = reportTier2(); //balance
                if (Global.options.isSubmitliquidity()) {
                    LOG.info("Liquidity info submitted:\n\t" + response1 + "\n\t" + response2);
                }
            } else {
                LOG.warn("Liquidity is not being sent : orders are not yet initialized");

            }
        } else {
            if (Global.options.isSubmitliquidity()) {
                LOG.warn("Liquidity is not being sent, a wall shift is happening. Will send on next execution.");
            }
        }
    }

    private String reportTier1() {
        String toReturn = "";

        Global.orderManager.fetchOrders();

        ArrayList<Order> orderList = Global.orderManager.getOrderList();

        if (SessionManager.sessionInterrupted())
            return ""; //external interruption

        LOG.debug("Active orders : " + orderList.size());

        Iterator<Order> it = orderList.iterator();
        while (it.hasNext()) {
            Order o = it.next();
            LOG.debug("order: " + o.getDigest());
        }
        if (SessionManager.sessionInterrupted())
            return ""; //external interruption

        if (verbose) {

            LOG.info(Global.exchange.getName() + "OLD NBTonbuy  : "
                    + Utils.formatNumber(Global.exchange.getLiveData().getNBTonbuy(), Settings.DEFAULT_PRECISION));
            LOG.info(Global.exchange.getName() + "OLD NBTonsell  : "
                    + Utils.formatNumber(Global.exchange.getLiveData().getNBTonsell(), Settings.DEFAULT_PRECISION));
        }

        double nbt_onsell = 0;
        double nbt_onbuy = 0;
        int sells = 0;
        int buys = 0;
        String digest = "";
        for (int i = 0; i < orderList.size(); i++) {
            Order tempOrder = orderList.get(i);
            digest = digest + tempOrder.getDigest();
            double toAdd = tempOrder.getAmount().getQuantity();
            if (verbose) {
                LOG.info(tempOrder.toString());
            }

            if (tempOrder.getType().equalsIgnoreCase(Constant.SELL)) {
                //Start summing up amounts of NBT
                nbt_onsell += toAdd;
                sells++;
            } else if (tempOrder.getType().equalsIgnoreCase(Constant.BUY)) {
                //Start summing up amounts of NBT
                nbt_onbuy += toAdd;
                buys++;
            }
        }
        //Update the order
        Global.exchange.getLiveData().setOrdersList(orderList);

        if (Global.conversion != 1 && Global.swappedPair) { //For swapped pair, need to convert the amounts to NBT
            nbt_onbuy = nbt_onbuy * Global.conversion;
            nbt_onsell = nbt_onsell * Global.conversion;
        }

        Global.exchange.getLiveData().setNBTonbuy(nbt_onbuy);
        Global.exchange.getLiveData().setNBTonsell(nbt_onsell);

        //Write to file timestamp,activeOrders, sells,buys, digest
        Date timeStamp = new Date();
        String timeStampString = timeStamp.toString();
        Long timeStampLong = Utils.getTimestampLong();
        String toWrite = timeStampString + " , " + orderList.size() + " , " + sells + " , " + buys + " , " + digest;
        logOrderCSV(toWrite);

        if (SessionManager.sessionInterrupted())
            return ""; //external interruption

        //Also update a json version of the output file
        //build the latest data into a JSONObject
        JSONObject latestOrders = new JSONObject();
        latestOrders.put("time_stamp", timeStampLong);
        latestOrders.put("active_orders", orderList.size());
        JSONArray jsonDigest = new JSONArray();
        for (Iterator<Order> order = orderList.iterator(); order.hasNext();) {

            JSONObject thisOrder = new JSONObject();
            Order _order = order.next();

            //issue 160 - convert all amounts in NBT

            double amount = _order.getAmount().getQuantity();
            //special case: swapped pair
            if (Global.conversion != 1) {
                if (Global.swappedPair)//For swapped pair, need to convert the amounts to NBT
                {
                    amount = _order.getAmount().getQuantity() * Global.conversion;
                }
            }

            thisOrder.put("order_id", _order.getId());
            thisOrder.put("time", _order.getInsertedDate().getTime());
            thisOrder.put("order_type", _order.getType());
            thisOrder.put("order_currency", _order.getPair().getOrderCurrency().getCode());
            thisOrder.put("amount", amount);
            thisOrder.put("payment_currency", _order.getPair().getPaymentCurrency().getCode());
            thisOrder.put("price", _order.getPrice().getQuantity());
            jsonDigest.add(thisOrder);
        }
        latestOrders.put("digest", jsonDigest);

        if (SessionManager.sessionInterrupted())
            return ""; //external interruption

        //now read the existing object if one exists
        JSONParser parser = new JSONParser();
        JSONObject orderHistory = new JSONObject();
        JSONArray orders = new JSONArray();
        try { //object already exists in file
            orderHistory = (JSONObject) parser.parse(FilesystemUtils.readFromFile(this.jsonFile_orders));
            orders = (JSONArray) orderHistory.get("orders");
        } catch (ParseException pe) {
            LOG.error("Unable to parse " + this.jsonFile_orders);
        }
        //add the latest orders to the orders array
        orders.add(latestOrders);
        //then save
        logOrderJSON(orderHistory);

        if (verbose) {
            LOG.info(Global.exchange.getName() + "Updated NBTonbuy  : "
                    + Utils.formatNumber(nbt_onbuy, Settings.DEFAULT_PRECISION));
            LOG.info(Global.exchange.getName() + "Updated NBTonsell  : "
                    + Utils.formatNumber(nbt_onsell, Settings.DEFAULT_PRECISION));
        }

        if (SessionManager.sessionInterrupted())
            return ""; //external interruption

        if (Global.options.isSubmitliquidity()) {
            //Call RPC

            double buySide;
            double sellSide;

            if (!Global.swappedPair) {
                buySide = Global.exchange.getLiveData().getNBTonbuy();
                sellSide = Global.exchange.getLiveData().getNBTonsell();
            } else {
                buySide = Global.exchange.getLiveData().getNBTonsell();
                sellSide = Global.exchange.getLiveData().getNBTonbuy();
            }

            toReturn = sendLiquidityInfoImpl(buySide, sellSide, 1);
        }
        return toReturn;
    }

    private JSONObject getBalanceHistory() throws ParseException {
        JSONParser parser = new JSONParser();
        JSONObject balanceHistory = (JSONObject) parser.parse(FilesystemUtils.readFromFile(this.jsonFile_balances));
        return balanceHistory;
    }

    private String reportTier2() {
        String toReturn = "";
        if (SessionManager.sessionInterrupted())
            return ""; //external interruption

        ApiResponse balancesResponse = Global.exchange.getTrade().getAvailableBalances(Global.options.getPair());
        if (balancesResponse.isPositive()) {
            PairBalance balance = (PairBalance) balancesResponse.getResponseObject();

            Amount NBTbalance = balance.getNBTAvailable();
            Amount PEGbalance = balance.getPEGAvailableBalance();

            double buyside = PEGbalance.getQuantity();
            double sellside = NBTbalance.getQuantity();

            //Log balances
            JSONObject latestBalances = new JSONObject();
            latestBalances.put("time_stamp", Utils.getTimestampLong());

            JSONArray availableBalancesArray = new JSONArray();
            JSONObject NBTBalanceJSON = new JSONObject();
            NBTBalanceJSON.put("amount", sellside);
            NBTBalanceJSON.put("currency", NBTbalance.getCurrency().getCode().toUpperCase());

            JSONObject PEGBalanceJSON = new JSONObject();
            PEGBalanceJSON.put("amount", buyside);
            PEGBalanceJSON.put("currency", PEGbalance.getCurrency().getCode().toUpperCase());

            availableBalancesArray.add(PEGBalanceJSON);
            availableBalancesArray.add(NBTBalanceJSON);

            latestBalances.put("balance-not-on-order", availableBalancesArray);

            if (SessionManager.sessionInterrupted())
                return ""; //external interruption

            //now read the existing object if one exists
            JSONObject balanceHistory = null;
            try {
                balanceHistory = getBalanceHistory();
            } catch (ParseException pe) {
                LOG.error("Unable to parse " + this.jsonFile_balances);
            }

            JSONArray balances = new JSONArray();
            try { //object already exists in file
                balances = (JSONArray) balanceHistory.get("balances");
            } catch (Exception e) {

            }

            //add the latest orders to the orders array
            balances.add(latestBalances);
            //then save
            logBalanceJSON(balanceHistory);

            buyside = Utils.round(buyside * Global.conversion, 2);

            if (Global.options.isSubmitliquidity()) {
                //Call RPC
                if (SessionManager.sessionInterrupted())
                    return ""; //external interruption
                toReturn = sendLiquidityInfoImpl(buyside, sellside, 2);
            }

        } else {
            LOG.error(balancesResponse.getError().toString());
        }
        return toReturn;
    }

    private String sendLiquidityInfoImpl(double buySide, double sellSide, int tier) {
        String toReturn = "";
        if (SessionManager.sessionInterrupted())
            return ""; //external interruption

        if (Global.rpcClient.isConnected()) {
            JSONObject responseObject;

            responseObject = Global.rpcClient.submitLiquidityInfo(Global.rpcClient.USDchar, buySide, sellSide,
                    tier);

            toReturn = "tier=" + tier + " buy=" + buySide + " sell=" + sellSide + " identifier="
                    + Global.rpcClient.generateIdentifier(tier) + " response=" + responseObject.toJSONString();
            if (null == responseObject) {
                LOG.error("Something went wrong while sending liquidityinfo");
            } else {
                LOG.debug(responseObject.toJSONString());
                if ((boolean) responseObject.get("submitted")) {
                    LOG.debug("RPC Liquidityinfo sent : " + " buyside : " + buySide + " sellside : " + sellSide);
                    if (verbose) {
                        JSONObject infoObject = Global.rpcClient.getLiquidityInfo(NuRPCClient.USDchar);
                        LOG.info("getliquidityinfo result : ");
                        LOG.info(infoObject.toJSONString());
                    }
                }
            }
        } else {
            LOG.error("Can't reach Nud client. ");
        }
        return toReturn;
    }

    public boolean isVerbose() {
        return verbose;
    }

    public void setVerbose(boolean verbose) {
        this.verbose = verbose;
    }

    public boolean isWallsBeingShifted() {
        return wallsBeingShifted;
    }

    public void setWallsBeingShifted(boolean wallsBeingShifted) {
        this.wallsBeingShifted = wallsBeingShifted;
    }

    public boolean isFirstOrdersPlaced() {
        return firstOrdersPlaced;
    }

    public void setFirstOrdersPlaced(boolean firstOrdersPlaced) {
        this.firstOrdersPlaced = firstOrdersPlaced;
    }

    //---------------- storage related -----------------

    private void logOrderCSV(String toWrite) {
        FilesystemUtils.writeToFile(toWrite, outputFile_orders, true);
    }

    private void logOrderJSON(JSONObject orderHistory) {
        FilesystemUtils.writeToFile(orderHistory.toJSONString(), jsonFile_orders, false);
    }

    private void logBalanceJSON(JSONObject balanceHistory) {
        FilesystemUtils.writeToFile(balanceHistory.toJSONString(), jsonFile_balances, false);
    }

}