You are viewing a single comment's thread from:

RE: Binance trading program

in #trading7 years ago

I've added a bit of functionality.

  1. We entered the variables as properties and made them automatically reflected.
  2. In addition to the beat coin, you can buy and sell with other currencies.
    Huh ~ It's not easy ... ^^
package com.binance.trading;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

import com.binance.api.client.BinanceApiClientFactory;
import com.binance.api.client.BinanceApiRestClient;
import com.binance.api.client.domain.account.Account;
import com.binance.api.client.domain.account.AssetBalance;
import com.binance.api.client.domain.account.NewOrder;
import com.binance.api.client.domain.account.Order;
import com.binance.api.client.domain.account.Trade;
import com.binance.api.client.domain.account.request.OrderRequest;
import com.binance.api.client.domain.general.ExchangeInfo;
import com.binance.api.client.domain.general.FilterType;
import com.binance.api.client.domain.general.SymbolFilter;
import com.binance.api.client.domain.general.SymbolInfo;
import com.binance.api.client.domain.market.TickerPrice;
import com.binance.api.client.exception.BinanceApiException;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import com.google.gson.stream.JsonReader;
import com.pengrad.telegrambot.TelegramBot;
import com.pengrad.telegrambot.request.SendMessage;

/**
 * Examples on how to get market data information such as the latest price of a
 * symbol, etc.
 */
public class MarketOrderTrading extends TimerTask {
    private final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
    private final String ITEMS_FILE_NAME = "trading_items.json";
    private final String CONFIG_FILE_NAME = "tradingBinance.properties";
    private final long CONFIG_REFLESH_DELAY_MILLISECONDS = 60000;
    private final Type ITEMS_TYPE = new TypeToken<Map<String, TradingItems>>() {}.getType();
    
    private final String API_KEY = "API_KEY";
    private final String SECRET_KEY = "SECRET_KEY";
    private final String TELEGRAM_TOKEN = "TELEGRAM_TOKEN";
    private final String TELEGRAM_CHAT_ID = "TELEGRAM_CHAT_ID";
    
    private final PropertiesConfiguration config = new PropertiesConfiguration();
    private final FileChangedReloadingStrategy fileChangedReloadingStrategy =new FileChangedReloadingStrategy();

    private static String[] PAIR_SYMBOLS = null;
    private final Map<String, Double> CURRENCY_INVEST_PRICES = new HashMap<String, Double>();
    
    private double GAP_TRADING_PERCENT = 70.0;
    private boolean IS_RISK_TASKING = false;
    private double FEE_PERCENT = 0.05;
    private double TAKE_EXTRA_PERCENT = 2.0;
    private double MIN_START_PERCENT = 1.0;
    private static int TIME_PERIOD_MILLISECONDS = 500;
    private final Map<String, Double> MIN_ORDER_VALUES = new HashMap<String, Double>();
    private int STATUS_LOGGING_CYCLE = 600;

    private final BinanceApiClientFactory factory = BinanceApiClientFactory.newInstance(API_KEY, SECRET_KEY);
    private final BinanceApiRestClient client = factory.newRestClient();
    private final TelegramBot telegramBot = new TelegramBot(TELEGRAM_TOKEN);

    private Map<String, TradingItems> items = null;
    private long exeCount = 0;
    private FileWriter fw;

    public MarketOrderTrading() {
        loadConfig();
        initialSettings();
    }

    private void loadConfig() {
        config.setFileName(CONFIG_FILE_NAME);
        try {
            config.load();
            setConfig();
        } catch (ConfigurationException e) {
            sendLogging(e.getMessage());
            e.printStackTrace();
        }
        
        fileChangedReloadingStrategy.setRefreshDelay(CONFIG_REFLESH_DELAY_MILLISECONDS);
        config.setReloadingStrategy(fileChangedReloadingStrategy);
    }
    
    private void setConfig() {
        PAIR_SYMBOLS = config.getStringArray("PAIR_SYMBOLS");
        
        CURRENCY_INVEST_PRICES.put("BTC", config.getDouble("CURRENCY_INVEST_PRICES.BTC", 0.002));
        CURRENCY_INVEST_PRICES.put("ETH", config.getDouble("CURRENCY_INVEST_PRICES.ETH", 0.02));
        CURRENCY_INVEST_PRICES.put("USDT", config.getDouble("CURRENCY_INVEST_PRICES.USDT", 11.0));
        CURRENCY_INVEST_PRICES.put("BNB", config.getDouble("CURRENCY_INVEST_PRICES.BNB", 2.0));
        
        GAP_TRADING_PERCENT  = config.getDouble("GAP_TRADING_PERCENT", 70.0);
        IS_RISK_TASKING = config.getBoolean("IS_RISK_TASKING", false);
        FEE_PERCENT = config.getDouble("FEE_PERCENT", 0.05);
        TAKE_EXTRA_PERCENT = config.getDouble("TAKE_EXTRA_PERCENT", 0.05);
        MIN_START_PERCENT = config.getDouble("MIN_START_PERCENT", 1.0);
        TIME_PERIOD_MILLISECONDS = config.getInt("TIME_PERIOD_MILLISECONDS", 500);
        
        MIN_ORDER_VALUES.put("BTC", config.getDouble("MIN_ORDER_VALUES.BTC", 0.001));
        MIN_ORDER_VALUES.put("ETH", config.getDouble("MIN_ORDER_VALUES.ETH", 0.01));
        MIN_ORDER_VALUES.put("USDT", config.getDouble("MIN_ORDER_VALUES.USDT", 10.0));
        MIN_ORDER_VALUES.put("BNB", config.getDouble("MIN_ORDER_VALUES.BNB", 1.0));

        STATUS_LOGGING_CYCLE = config.getInt("STATUS_LOGGING_CYCLE");   
        
    }
    
    private void initialSettings() {
        if (items == null) {
            loadItems();
        }
        
        final Iterator<String> itemKeys = items.keySet().iterator();
        while (itemKeys.hasNext()) {
            final String key = itemKeys.next();
            if ( ArrayUtils.contains(PAIR_SYMBOLS, key) == false ) {
                itemKeys.remove();
            }
        }
        
        for (int i = 0; i < PAIR_SYMBOLS.length; i++) {
            final String pairSymbol = PAIR_SYMBOLS[i];
            if (items.containsKey(pairSymbol) == false) {
                initialBasicSetting(pairSymbol);
                initialSetting(items.get(pairSymbol));
            }
        }
    }
    
    private void initialBasicSetting(final String pairSymbol) {
        TradingItems item;
        if (items.containsKey(pairSymbol)) {
            item = this.items.get(pairSymbol);
        } else {
            item = new TradingItems();
            items.put(pairSymbol, item);
        }
        final String[] symbols = StringUtils.split(pairSymbol, '/');
        item.setTargetSymbol(symbols[0]);
        item.setCurrencySymbol(symbols[1]);
        item.setPairSymbol(symbols[0] + symbols[1]);
        getLotSize(item);
    }

    private void initialSetting(final TradingItems item) {
        final List<Order> openOrders = getOpenOrders(item.getPairSymbol());
        if (openOrders.size() > 0) {
            item.setWaiting(true);
            return;
        } else {
            item.setWaiting(false);
        }

        final TickerPrice nowTickerPrice = getPrice(item.getPairSymbol());
        final double nowPrice = Double.parseDouble(nowTickerPrice.getPrice());

        Trade trade = getLastTrade(item.getPairSymbol());
        double bagicPrice = 0.0;
        if (trade != null) {
            bagicPrice = Double.parseDouble(trade.getPrice());
        } else {
            bagicPrice = nowPrice;
        }

        item.setTopPrice(bagicPrice);
        item.setBottomPrice(bagicPrice);
        item.setLastOrderPrice(bagicPrice);

        sendLogging(item.getPairSymbol() +  ", Bagic Price : " + toString(bagicPrice), false);
    }

    private void getLotSize(final TradingItems item) {
        final ExchangeInfo exchangeInfo = client.getExchangeInfo();
        final SymbolInfo symbolInfo = exchangeInfo.getSymbolInfo(item.getPairSymbol());
        final SymbolFilter priceFilter = symbolInfo.getSymbolFilter(FilterType.LOT_SIZE);
        item.setMinQty(Double.parseDouble(priceFilter.getMinQty()));
        item.setStepSize(Double.parseDouble(priceFilter.getStepSize()));
    }

    private TickerPrice getPrice(final String pairSymbol) {
        return client.getPrice(pairSymbol);
    }

    private List<Order> getOpenOrders(final String pairSymbol) {
        return client.getOpenOrders(new OrderRequest(pairSymbol));
    }

    private Trade getLastTrade(final String pairSymbol) {
        Trade trade = null;
        List<Trade> trades = client.getMyTrades(pairSymbol, 1);
        if (trades.size() > 0) {
            trade = trades.get(0);
        }
        return trade;
    }

    private AssetBalance getAssetBalance(final String symbol) {
        final Account account = client.getAccount(6000000L, System.currentTimeMillis());
        return account.getAssetBalance(symbol);
    }

    private void watchTrading(final TradingItems item) {
        if (item.isWaiting()) {
            initialSetting(item);
            return;
        }
        final double lastOrderPrice = item.getLastOrderPrice();
        final TickerPrice nowTickerPrice = getPrice(item.getPairSymbol());
        final double nowPrice = Double.parseDouble(nowTickerPrice.getPrice());
        item.setNowPrice(nowPrice);
        
        if (nowPrice < lastOrderPrice) { // Buy
            item.setBuy(true);
            watchBuyTrading(item);
        } else { // Sell
            item.setBuy(false);
            watchSellTrading(item);
        }
    }

    private void watchBuyTrading(final TradingItems item) {
        final double bottomPrice = item.getBottomPrice();
        final double lastOrderPrice = item.getLastOrderPrice();
        final double nowPrice = item.getNowPrice();

        if (nowPrice < bottomPrice) {
            item.setBottomPrice(nowPrice);
        } else {

            if (this.IS_RISK_TASKING == false) {
                final double breakEvenPrice = lastOrderPrice
                        - nowPrice * (TAKE_EXTRA_PERCENT + FEE_PERCENT) / 100.0;
                if (nowPrice > breakEvenPrice) {
                    return;
                }
            }

            if (nowPrice - bottomPrice < nowPrice * (MIN_START_PERCENT / 100)) {
                return;
            }

            final double maxPrice = lastOrderPrice - (lastOrderPrice - bottomPrice) * (GAP_TRADING_PERCENT / 100.0);
            if (nowPrice < maxPrice) {
                return;
            }
            orderBuying(item, nowPrice);
            initialSetting(item);
        }
    }

    private void watchSellTrading(final TradingItems item) {
        final double topPrice = item.getTopPrice();
        final double lastOrderPrice = item.getLastOrderPrice();
        final double nowPrice = item.getNowPrice();
        
        if (nowPrice > topPrice) {
            item.setTopPrice(nowPrice);
        } else {

            if (this.IS_RISK_TASKING == false) {
                final double breakEvenPrice = lastOrderPrice
                        + nowPrice * (TAKE_EXTRA_PERCENT + FEE_PERCENT * 2) / 100.0;
                if (nowPrice < breakEvenPrice) {
                    return;
                }
            }

            if (topPrice - nowPrice < nowPrice * (MIN_START_PERCENT / 100)) {
                return;
            }

            final double minPrice = lastOrderPrice + (topPrice - lastOrderPrice) * (GAP_TRADING_PERCENT / 100.0);
            if (nowPrice > minPrice) {
                return;
            }
            orderSelling(item, nowPrice);
            initialSetting(item);
        }
    }

    private String getStatusLogging(final TradingItems item) {
        return item.getPairSymbol() + " -- " 
                        + (item.isBuy() ? "Buy" : "Sell") 
                        + ", N:" + toString(item.getNowPrice())
                        + ", T:" + toString(item.getTopPrice()) 
                        + ", B:"+ toString(item.getBottomPrice()) 
                        + ", L:" + toString(item.getLastOrderPrice());
    }
    
    private void sendStatusLogging() {
        if (exeCount % STATUS_LOGGING_CYCLE == 0) {
            final StringBuffer sb = new StringBuffer();
            for (int i = 0; i < PAIR_SYMBOLS.length; i++) {
                final String pairSymbol = PAIR_SYMBOLS[i];
                final TradingItems item = items.get(pairSymbol);
                sb.append(getStatusLogging(item)).append(System.lineSeparator());
            }
            sendLogging(sb.toString(), false);
        }
    }

    private void orderBuying(final TradingItems item, final double price) {
        final String currencySymbol = item.getCurrencySymbol();
        final double minOrderValue = MIN_ORDER_VALUES.get(currencySymbol);
        final AssetBalance currencyBalance = getAssetBalance(currencySymbol);
        final double freeQty = Double.parseDouble(currencyBalance.getFree());
        final double currencyInvestPrice = CURRENCY_INVEST_PRICES.get(item.getCurrencySymbol());

        String buyQty = null;
        if (freeQty < minOrderValue) {
            sendLogging(item.getPairSymbol() + ", BTC Free Qty : " + 
                    freeQty + " --- There is not enough currency.", false);
            return;
        } else if (freeQty < currencyInvestPrice) {
            buyQty = toOrderQty(item, freeQty / price);
        } else {
            buyQty = toOrderQty(item, currencyInvestPrice / price);
        }

        try {
            client.newOrder(NewOrder.marketBuy(item.getPairSymbol(), buyQty));
            sendLogging(item.getPairSymbol() + " -- Buy : " + toString(price) + ", Qty : " + buyQty);
        } catch (BinanceApiException e) {
            sendLogging(e.getMessage());
            e.printStackTrace();
        }
    }

    private void orderSelling(final TradingItems item, final double price) {
        final String currencySymbol = item.getCurrencySymbol();
        final String targetSymbol = item.getTargetSymbol();
        final double currencyInvestPrice = CURRENCY_INVEST_PRICES.get(currencySymbol);
        final double minOrderValue = MIN_ORDER_VALUES.get(currencySymbol);
        
        final AssetBalance balance = getAssetBalance(targetSymbol);
        final double freeQty = Double.parseDouble(balance.getFree());
        final double sellMaxQty =  currencyInvestPrice / price;
        final double sellMinQty =  minOrderValue / price;
        String sellQty = null;
        if (sellMinQty > freeQty) {
            sendLogging(item.getPairSymbol() + ", Free Qty : " + 
                        freeQty + " --- There is not enough target.", false);
            return;
        } else if (sellMaxQty > freeQty) {
            // BNB
            if (StringUtils.equals("BNB", targetSymbol) || StringUtils.equals("BNB", currencySymbol)) {
                sendLogging(item.getPairSymbol() + ", Free Qty : " + 
                        freeQty + " --- There is not enough target.", false);
                return;
            }
            sellQty = toOrderQty(item, freeQty);
        } else {
            sellQty = toOrderQty(item, sellMaxQty);
        }
        
        try {
            client.newOrder(NewOrder.marketSell(item.getPairSymbol(), sellQty));
            sendLogging(item.getPairSymbol() + " -- Sell : " + toString(price) + ", Qty : " + sellQty);
        } catch (BinanceApiException e) {
            sendLogging(e.getMessage());
            e.printStackTrace();
        }
    }

    private String toOrderQty(final TradingItems item, final double qty) {
        String strOrderQty = null;
        if (qty >= item.getMinQty()) {
            double orderQty = qty - qty % item.getStepSize();
            strOrderQty = toString(orderQty);
        }
        return strOrderQty;
    }

    private String toString(double num) {
        return String.format("%.9f", num);
    }

    private void sendLogging(final String message) {
        System.out.println(addDateString(message));
        sendToBot(message);
    }

    private void sendLogging(final String message, final boolean sendBot) {
        if (sendBot) {
            sendLogging(message);
        } else {
            System.out.println(addDateString(message));
        }
    }

    private String addDateString(final String message) {
        final Date nowDate = new Date();
        return message + ":: " + DATE_FORMAT.format(nowDate);
    }

    private void sendToBot(final String message) {
        try {
            final SendMessage request = new SendMessage(TELEGRAM_CHAT_ID, addDateString(message));
            telegramBot.execute(request);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private void saveItems() {
        final Gson gson = new Gson();
        final String jsonItems = gson.toJson(items);
        try {
            fw = new FileWriter(ITEMS_FILE_NAME);
            fw.write(jsonItems);
            fw.flush();
        } catch (IOException e) {
            sendLogging(e.getMessage());
            e.printStackTrace();
        }
    }
    
    private void loadItems() {
        JsonReader reader;
        Gson gson = new Gson();
        try {
            reader = new JsonReader(new FileReader(ITEMS_FILE_NAME));
            this.items = gson.fromJson(reader, ITEMS_TYPE);
        } catch (FileNotFoundException e) {
            items = new HashMap<String, TradingItems>();
            e.printStackTrace();
        }
    }
    
    @Override
    public void run() {
        if (fileChangedReloadingStrategy.reloadingRequired()) {
            setConfig();
            initialSettings();
        }
        
        for (int i = 0; i < PAIR_SYMBOLS.length; i++) {
            final String pairSymbol = PAIR_SYMBOLS[i];
            final TradingItems item = items.get(pairSymbol);
            watchTrading(item);
        }
        saveItems();
        sendStatusLogging();
        
        exeCount++;
    }

    public static void main(String[] args) {
        final TimerTask task = new MarketOrderTrading();
        final ScheduledExecutorService service =
        Executors.newSingleThreadScheduledExecutor();
        service.scheduleWithFixedDelay(task, TIME_PERIOD_MILLISECONDS, 
                TIME_PERIOD_MILLISECONDS, TimeUnit.MILLISECONDS);
    }

}