바이낸스 라이브러리를 이용하여 암호화폐를 자동으로 매매하는 프로그램을 제가 사용할려고 작성했습니다.
추세를 지켜보면서 매매를 하는 것이 너무 피곤하고 하여 제가 매매하는 로직을 프로그램으로 구현을 한 것입니다.
손해를 볼 수도 있으니, 무작정 사용하시는 것은 권해드리고 싶지는 않아요. 참고하시고 힌트를 얻어시기를 바래요.
로직을 짧게 소개를 할께요.
- 기준 금액은 마지막 매매 가격이나 현재 가격이다.
- 기준 금액보다 현재 가격이 크면 매도, 작으면 매수를 한다.
- 매수: 정해진 퍼센트보다 내리고 min가격에서 정해진 퍼센트와 가격이 오르면 시장가로 매수한다.
- 매도: 정해진 퍼센트보다 오르고 max가격에서 정해진 퍼센트와 가격이 내리면 시장가로 매도한다.
- 매매가 일어나면 텔레그램으로 메시지를 보낸다.
- 정해진 간격으로 로그를 남긴다.
- 가격 데이터를 json으로 매번 저장을 해서 프로그램을 다시 내리고 올릴때 그 데이터를 참고한다.
- 정해진 시간 간격으로 시장가를 가져와서 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);
}
}