바이낸스 자동매매 하는 프로그램

in #trading7 years ago (edited)

바이낸스 라이브러리를 이용하여 암호화폐를 자동으로 매매하는 프로그램을 제가 사용할려고 작성했습니다.
추세를 지켜보면서 매매를 하는 것이 너무 피곤하고 하여 제가 매매하는 로직을 프로그램으로 구현을 한 것입니다.
손해를 볼 수도 있으니, 무작정 사용하시는 것은 권해드리고 싶지는 않아요. 참고하시고 힌트를 얻어시기를 바래요.

로직을 짧게 소개를 할께요.

  1. 기준 금액은 마지막 매매 가격이나 현재 가격이다.
  2. 기준 금액보다 현재 가격이 크면 매도, 작으면 매수를 한다.
  3. 매수: 정해진 퍼센트보다 내리고 min가격에서 정해진 퍼센트와 가격이 오르면 시장가로 매수한다.
  4. 매도: 정해진 퍼센트보다 오르고 max가격에서 정해진 퍼센트와 가격이 내리면 시장가로 매도한다.
  5. 매매가 일어나면 텔레그램으로 메시지를 보낸다.
  6. 정해진 간격으로 로그를 남긴다.
  7. 가격 데이터를 json으로 매번 저장을 해서 프로그램을 다시 내리고 올릴때 그 데이터를 참고한다.
  8. 정해진 시간 간격으로 시장가를 가져와서 1-7을 반복한다.

아래는 제가 작성한 소스 입니다.


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.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.lang3.ArrayUtils;

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 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 String CURRENCY_SYMBOL = "BTC";
    private final static String[] TARGET_SYMBOLS = { "ETH"};
    private final double CURRENCY_INVEST_PRICE = 0.002;
    private final double GAP_TRADING_PERCENT = 70.0;
    private final boolean IS_RISK_TASKING = false;
    private final double FEE_PERCENT = 0.05;
    private final double TAKE_EXTRA_PERCENT = 2.0;
    private final double MIN_START_PERCENT = 2.0;
    private final static int TIME_PERIOD_MILLISECONDS = 500;
    private final double MIN_ORDER_VALUE = 0.001;
    
    private final 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 = new HashMap<String, TradingItems>();
    private long exeCount = 0;
    private FileWriter fw;

    public MarketOrderTrading() {
        initialSettings();
    }

    
    private void initialSettings() {
        loadItems();
        for (final String key : items.keySet()) {
            if ( ArrayUtils.contains(TARGET_SYMBOLS, key) == false ) {
                items.remove(key);
            }
        }
        
        for (int i = 0; i < TARGET_SYMBOLS.length; i++) {
            final String targetSymbol = TARGET_SYMBOLS[i];
            if (items.containsKey(targetSymbol) == false) {
                initialBasicSetting(targetSymbol);
                initialSetting(items.get(targetSymbol));
            }
        }
    }
    
    private void initialBasicSetting(final String targetSymbol) {
        TradingItems item;
        if (items.containsKey(targetSymbol)) {
            item = this.items.get(targetSymbol);
        } else {
            item = new TradingItems();
            items.put(targetSymbol, item);
        }
        item.setTargetSymbol(targetSymbol);
        item.setPairSymbol(targetSymbol + CURRENCY_SYMBOL);
        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 getCurrencyAssetBalance() {
        return getAssetBalance(CURRENCY_SYMBOL);
    }

    private AssetBalance getTargetAssetBalance(final String targetSymbol) {
        return getAssetBalance(targetSymbol);
    }

    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 < TARGET_SYMBOLS.length; i++) {
                final String targetSymbol = TARGET_SYMBOLS[i];
                final TradingItems item = items.get(targetSymbol);
                sb.append(getStatusLogging(item)).append(System.lineSeparator());
            }
            sendLogging(sb.toString(), false);
        }
    }

    private void orderBuying(final TradingItems item, final double price) {
        final AssetBalance balance = getCurrencyAssetBalance();
        final double freeQty = Double.parseDouble(balance.getFree());
        String buyQty = null;
        if (freeQty < MIN_ORDER_VALUE) {
            sendLogging(item.getPairSymbol() + ", BTC Free Qty : " + freeQty + " --- There is not enough currency.", false);
            return;
        } else if (freeQty < CURRENCY_INVEST_PRICE) {
            buyQty = toOrderQty(item, freeQty / price);
        } else {
            buyQty = toOrderQty(item, CURRENCY_INVEST_PRICE / 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 AssetBalance balance = getTargetAssetBalance(item.getTargetSymbol());
        final double freeQty = Double.parseDouble(balance.getFree());
        final double sellMaxQty =  CURRENCY_INVEST_PRICE / price;
        final double sellMinQty =  MIN_ORDER_VALUE / price;
        String sellQty = null;
        if (sellMinQty > freeQty) {
            sendLogging(item.getPairSymbol() + ", Free Qty : " + freeQty + " --- There is not enough target.", false);
            return;
        } else if (sellMaxQty > freeQty) {
            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) {
            e.printStackTrace();
        }
    }
    
    

    @Override
    public void run() {
        for (int i = 0; i < TARGET_SYMBOLS.length; i++) {
            final String targetSymbol = TARGET_SYMBOLS[i];
            final TradingItems item = items.get(targetSymbol);
            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);
    }

}

Sort:  
Loading...