diff --git a/README.md b/README.md index b568d1c..b0e4420 100644 --- a/README.md +++ b/README.md @@ -14,18 +14,28 @@ https://github.com/Nubebuster/CryptoProfitTracker/releases 4. Go to the 'Main' tab and set your pairing. For example: ADAUSDT ## How to export data from Binance + +#### For a max range of 3 months: +This will generate a .xlsx file which you can use for this program 1. Go to your trade history 2. Click on the tab 'Trade History' 3. Click on 'Export Recent Trade History' -This will generate a .xlsx file which you can use for this program + +#### Limitless (max 3 exports per month, binance cap) +This will generate a .csv file which you can use for this program +1. Go to your trade history +2. Click on the tab 'Trade History' +3. Click on 'Generate All Trade Statements' + + ## TODO - Test accurate valuation for non xUSDT pairs - Add support for mixing trading pairs. For example: ETHUSDT in conjunction with ETHBTC - Add more exchange export support - Add profit calculation for all trading pairs - UI with graphs to plot your profits over time -- Add support for .csv binance export # Troubleshooting If the program does not work properly, please run it with a command line to see error stacktraces. -These stacktraces can be reported in the github issues section of this repository. +These stacktraces can be reported in the github issues section of this repository. +Be sure to explain how to reproduce the problem. Also include stacktraces. \ No newline at end of file diff --git a/pom.xml b/pom.xml index a8ee8e4..d61dc0c 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.nubebuster.cryptoprofittracker cryptoprofittracker - 0.0.1 + 0.0.3 diff --git a/src/main/java/com/nubebuster/cryptoprofittracker/BinanceProfitTracker.java b/src/main/java/com/nubebuster/cryptoprofittracker/BinanceProfitTracker.java index ebe1e95..3e22bf6 100644 --- a/src/main/java/com/nubebuster/cryptoprofittracker/BinanceProfitTracker.java +++ b/src/main/java/com/nubebuster/cryptoprofittracker/BinanceProfitTracker.java @@ -13,8 +13,7 @@ import org.apache.poi.xssf.usermodel.XSSFWorkbook; import javax.swing.*; -import java.io.File; -import java.io.FileWriter; +import java.io.*; import java.math.BigDecimal; import java.math.MathContext; import java.rmi.UnexpectedException; @@ -69,14 +68,34 @@ public static void main(String[] args) { ui.printCalculationsButton.setEnabled(true); return; } - OPCPackage pkg = OPCPackage.open(dataFile); - Workbook wb = new XSSFWorkbook(pkg); - Sheet sheet = wb.getSheetAt(0); - Iterator rows = sheet.rowIterator(); + List orders = null; + if (dataFile.getName().endsWith(".xlsx")) { + OPCPackage pkg = OPCPackage.open(dataFile); + Workbook wb = new XSSFWorkbook(pkg); + Sheet sheet = wb.getSheetAt(0); + Iterator rows = sheet.rowIterator(); + orders = parseOrders(ui.ticker.getText().toUpperCase(), rows); + try { + pkg.close(); + } catch (FileNotFoundException ex) { + //if its open in another program + } + } else if (dataFile.getName().endsWith(".csv")) { + List data = new ArrayList(); + BufferedReader br = new BufferedReader(new FileReader(dataFile)); + String line = ""; + while ((line = br.readLine()) != null) + data.add(line); + orders = parseOrders(ui.ticker.getText().toUpperCase(), data); + } else { + System.err.println("Unsupported data format. Current support: [.xlsx, .csv]"); + ui.output.setText("Unsupported data format. Current support: [.xlsx, .csv]"); + ui.printCalculationsButton.setEnabled(true); + return; + } BinanceProfitTracker binanceProfitTracker = new BinanceProfitTracker(ui, ui.apiKeyTextField.getText(), ui.secretKeyTextField.getText()); - binanceProfitTracker.printCalculations(ui.ticker.getText(), bnbFee, rows); - pkg.close(); + binanceProfitTracker.printCalculations(ui.ticker.getText().toUpperCase(), bnbFee, orders); } catch (Exception ex) { ex.printStackTrace(); } @@ -95,7 +114,7 @@ public static void main(String[] args) { ui.secretKeyTextField.getText() + "\ndataFile=" + ui.dataTextField.getText() + "\nNote: this file should not be edited manually."); fr.flush(); fr.close(); - System.out.println("Saved data to " + configFile.getPath()); + System.out.println("Saved settings to " + configFile.getPath()); } catch (Exception e) { e.printStackTrace(); } @@ -123,12 +142,44 @@ public BinanceApiRestClient getBinanceClient() { return client; } - public void printCalculations(String pair, double bnbFeeValue, Iterator rows) throws Exception { + /** + * For parsing .csv format + * + * @param pair + * @param data + * @return + */ + private static List parseOrders(String pair, List data) { List orders = new ArrayList(); + for (String r : data) { + if (r.startsWith("Date")) //headers + continue; + String[] row = r.replaceAll("(\"[^\",]+),([^\"]+\")", "$1$2").replace("\"", "").split(","); + String linePair = row[1]; + if (!linePair.equals(pair)) + continue; - long oldest = Long.MAX_VALUE; - long newest = Long.MIN_VALUE; + long time = CryptoProfitTrackerUtils.convertToTimeStamp(row[0]); + boolean buy = row[2].equals("BUY"); + double price = Double.parseDouble(row[3]); + double amount = Double.parseDouble(row[4].replaceAll("[^\\d.]", "")); + double total = Double.parseDouble(row[5].replaceAll("[^\\d.]", "")); + double fee = Double.parseDouble(row[6].replaceAll("[^\\d.]", "")); + String feeCoin = row[6].replaceAll("[\\d.]", ""); + orders.add(new TradeOrder(pair, buy, price, amount, total, fee, feeCoin, time)); + } + return orders; + } + /** + * For parsing .xlsx format + * + * @param pair + * @param rows + * @return + */ + private static List parseOrders(String pair, Iterator rows) { + List orders = new ArrayList(); while (rows.hasNext()) { Row row = rows.next(); if (row.getRowNum() == 0) //headers @@ -138,9 +189,6 @@ public void printCalculations(String pair, double bnbFeeValue, Iterator row continue; long time = CryptoProfitTrackerUtils.convertToTimeStamp(row.getCell(0).getStringCellValue()); - if (time < oldest) oldest = time; - if (time > newest) newest = time; - boolean buy = row.getCell(2).getStringCellValue().equals("BUY"); double price = Double.parseDouble(row.getCell(3).getStringCellValue()); double amount = Double.parseDouble(row.getCell(4).getStringCellValue()); @@ -150,8 +198,26 @@ public void printCalculations(String pair, double bnbFeeValue, Iterator row orders.add(new TradeOrder(pair, buy, price, amount, total, fee, feeCoin, time)); } + return orders; + } -// //collect all candles from the first to last transaction to be able to convert at timestamps without querying. + /** + * @param pair needs to be in upper case. Example: ADAUSDT + * @param bnbFeeValue percentage formatted to double + * @param orders + * @throws Exception + */ + public void printCalculations(String pair, double bnbFeeValue, List orders) throws Exception { + +// //collect all candles from the first to last transaction to be able to convert at timestamps without querying. +// long oldest = Long.MAX_VALUE; +// long newest = Long.MIN_VALUE; +// for(TradeOrder order : getOrders(pair, rows)) { +// long time = order.getTime(); +// if (time < oldest) oldest = time; +// if (time > newest) newest = time; +// } +// // List candles = candleStickCollector.getCandlesCollectWhenMissing(pair, oldest - CryptoProfitTrackerUtils.convertCandleStickIntervalToMs(CACHE_PRECISION), newest + CryptoProfitTrackerUtils.convertCandleStickIntervalToMs(CACHE_PRECISION), // CACHE_PRECISION); @@ -186,7 +252,7 @@ public void printCalculations(String pair, double bnbFeeValue, Iterator row } log("Data for " + pair); - log("#Orders (BUY+SELL): " + orders.size()); + log("#Trades (BUY+SELL): " + orders.size()); log("Volume: " + roundedToSignificance(volume)); log("Sub Total Profit: " + roundedToSignificance(cumProfit)); @@ -200,7 +266,7 @@ public void printCalculations(String pair, double bnbFeeValue, Iterator row } /** - * @param candles to get the price from + * @param candles to get the price from * @param timestamp of the price you want to know * @returns the closing price of the candle. -1 if no candle was found. * You can use {@link #loadHistoricalPrice(String, long)} if this function returns -1.