Skip to content

Commit 348630b

Browse files
committed
Added .csv support.
You can now use the long term exports from Binance
1 parent 7fbcceb commit 348630b

File tree

3 files changed

+98
-22
lines changed

3 files changed

+98
-22
lines changed

README.md

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,28 @@ https://github.com/Nubebuster/CryptoProfitTracker/releases
1414
4. Go to the 'Main' tab and set your pairing. For example: ADAUSDT
1515

1616
## How to export data from Binance
17+
18+
#### For a max range of 3 months:
19+
This will generate a .xlsx file which you can use for this program
1720
1. Go to your trade history
1821
2. Click on the tab 'Trade History'
1922
3. Click on 'Export Recent Trade History'
2023

21-
This will generate a .xlsx file which you can use for this program
24+
25+
#### Limitless (max 3 exports per month, binance cap)
26+
This will generate a .csv file which you can use for this program
27+
1. Go to your trade history
28+
2. Click on the tab 'Trade History'
29+
3. Click on 'Generate All Trade Statements'
30+
31+
2232
## TODO
2333
- Test accurate valuation for non xUSDT pairs
2434
- Add support for mixing trading pairs. For example: ETHUSDT in conjunction with ETHBTC
2535
- Add more exchange export support
2636
- Add profit calculation for all trading pairs
2737
- UI with graphs to plot your profits over time
28-
- Add support for .csv binance export
2938
# Troubleshooting
3039
If the program does not work properly, please run it with a command line to see error stacktraces.
31-
These stacktraces can be reported in the github issues section of this repository.
40+
These stacktraces can be reported in the github issues section of this repository.
41+
Be sure to explain how to reproduce the problem. Also include stacktraces.

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.nubebuster.cryptoprofittracker</groupId>
88
<artifactId>cryptoprofittracker</artifactId>
9-
<version>0.0.1</version>
9+
<version>0.0.3</version>
1010
<build>
1111
<plugins>
1212
<plugin>

src/main/java/com/nubebuster/cryptoprofittracker/BinanceProfitTracker.java

Lines changed: 84 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
1414

1515
import javax.swing.*;
16-
import java.io.File;
17-
import java.io.FileWriter;
16+
import java.io.*;
1817
import java.math.BigDecimal;
1918
import java.math.MathContext;
2019
import java.rmi.UnexpectedException;
@@ -69,14 +68,34 @@ public static void main(String[] args) {
6968
ui.printCalculationsButton.setEnabled(true);
7069
return;
7170
}
72-
OPCPackage pkg = OPCPackage.open(dataFile);
73-
Workbook wb = new XSSFWorkbook(pkg);
74-
Sheet sheet = wb.getSheetAt(0);
75-
Iterator<Row> rows = sheet.rowIterator();
71+
List<TradeOrder> orders = null;
72+
if (dataFile.getName().endsWith(".xlsx")) {
73+
OPCPackage pkg = OPCPackage.open(dataFile);
74+
Workbook wb = new XSSFWorkbook(pkg);
75+
Sheet sheet = wb.getSheetAt(0);
76+
Iterator<Row> rows = sheet.rowIterator();
77+
orders = parseOrders(ui.ticker.getText().toUpperCase(), rows);
78+
try {
79+
pkg.close();
80+
} catch (FileNotFoundException ex) {
81+
//if its open in another program
82+
}
83+
} else if (dataFile.getName().endsWith(".csv")) {
84+
List<String> data = new ArrayList<String>();
85+
BufferedReader br = new BufferedReader(new FileReader(dataFile));
86+
String line = "";
87+
while ((line = br.readLine()) != null)
88+
data.add(line);
89+
orders = parseOrders(ui.ticker.getText().toUpperCase(), data);
90+
} else {
91+
System.err.println("Unsupported data format. Current support: [.xlsx, .csv]");
92+
ui.output.setText("Unsupported data format. Current support: [.xlsx, .csv]");
93+
ui.printCalculationsButton.setEnabled(true);
94+
return;
95+
}
7696
BinanceProfitTracker binanceProfitTracker = new BinanceProfitTracker(ui, ui.apiKeyTextField.getText(),
7797
ui.secretKeyTextField.getText());
78-
binanceProfitTracker.printCalculations(ui.ticker.getText(), bnbFee, rows);
79-
pkg.close();
98+
binanceProfitTracker.printCalculations(ui.ticker.getText().toUpperCase(), bnbFee, orders);
8099
} catch (Exception ex) {
81100
ex.printStackTrace();
82101
}
@@ -95,7 +114,7 @@ public static void main(String[] args) {
95114
ui.secretKeyTextField.getText() + "\ndataFile=" + ui.dataTextField.getText() + "\nNote: this file should not be edited manually.");
96115
fr.flush();
97116
fr.close();
98-
System.out.println("Saved data to " + configFile.getPath());
117+
System.out.println("Saved settings to " + configFile.getPath());
99118
} catch (Exception e) {
100119
e.printStackTrace();
101120
}
@@ -123,12 +142,44 @@ public BinanceApiRestClient getBinanceClient() {
123142
return client;
124143
}
125144

126-
public void printCalculations(String pair, double bnbFeeValue, Iterator<Row> rows) throws Exception {
145+
/**
146+
* For parsing .csv format
147+
*
148+
* @param pair
149+
* @param data
150+
* @return
151+
*/
152+
private static List<TradeOrder> parseOrders(String pair, List<String> data) {
127153
List<TradeOrder> orders = new ArrayList<TradeOrder>();
154+
for (String r : data) {
155+
if (r.startsWith("Date")) //headers
156+
continue;
157+
String[] row = r.replaceAll("(\"[^\",]+),([^\"]+\")", "$1$2").replace("\"", "").split(",");
158+
String linePair = row[1];
159+
if (!linePair.equals(pair))
160+
continue;
128161

129-
long oldest = Long.MAX_VALUE;
130-
long newest = Long.MIN_VALUE;
162+
long time = CryptoProfitTrackerUtils.convertToTimeStamp(row[0]);
163+
boolean buy = row[2].equals("BUY");
164+
double price = Double.parseDouble(row[3]);
165+
double amount = Double.parseDouble(row[4].replaceAll("[^\\d.]", ""));
166+
double total = Double.parseDouble(row[5].replaceAll("[^\\d.]", ""));
167+
double fee = Double.parseDouble(row[6].replaceAll("[^\\d.]", ""));
168+
String feeCoin = row[6].replaceAll("[\\d.]", "");
169+
orders.add(new TradeOrder(pair, buy, price, amount, total, fee, feeCoin, time));
170+
}
171+
return orders;
172+
}
131173

174+
/**
175+
* For parsing .xlsx format
176+
*
177+
* @param pair
178+
* @param rows
179+
* @return
180+
*/
181+
private static List<TradeOrder> parseOrders(String pair, Iterator<Row> rows) {
182+
List<TradeOrder> orders = new ArrayList<TradeOrder>();
132183
while (rows.hasNext()) {
133184
Row row = rows.next();
134185
if (row.getRowNum() == 0) //headers
@@ -138,9 +189,6 @@ public void printCalculations(String pair, double bnbFeeValue, Iterator<Row> row
138189
continue;
139190

140191
long time = CryptoProfitTrackerUtils.convertToTimeStamp(row.getCell(0).getStringCellValue());
141-
if (time < oldest) oldest = time;
142-
if (time > newest) newest = time;
143-
144192
boolean buy = row.getCell(2).getStringCellValue().equals("BUY");
145193
double price = Double.parseDouble(row.getCell(3).getStringCellValue());
146194
double amount = Double.parseDouble(row.getCell(4).getStringCellValue());
@@ -150,8 +198,26 @@ public void printCalculations(String pair, double bnbFeeValue, Iterator<Row> row
150198

151199
orders.add(new TradeOrder(pair, buy, price, amount, total, fee, feeCoin, time));
152200
}
201+
return orders;
202+
}
153203

154-
// //collect all candles from the first to last transaction to be able to convert at timestamps without querying.
204+
/**
205+
* @param pair needs to be in upper case. Example: ADAUSDT
206+
* @param bnbFeeValue percentage formatted to double
207+
* @param orders
208+
* @throws Exception
209+
*/
210+
public void printCalculations(String pair, double bnbFeeValue, List<TradeOrder> orders) throws Exception {
211+
212+
// //collect all candles from the first to last transaction to be able to convert at timestamps without querying.
213+
// long oldest = Long.MAX_VALUE;
214+
// long newest = Long.MIN_VALUE;
215+
// for(TradeOrder order : getOrders(pair, rows)) {
216+
// long time = order.getTime();
217+
// if (time < oldest) oldest = time;
218+
// if (time > newest) newest = time;
219+
// }
220+
//
155221
// List<Candlestick> candles = candleStickCollector.getCandlesCollectWhenMissing(pair, oldest - CryptoProfitTrackerUtils.convertCandleStickIntervalToMs(CACHE_PRECISION), newest + CryptoProfitTrackerUtils.convertCandleStickIntervalToMs(CACHE_PRECISION),
156222
// CACHE_PRECISION);
157223

@@ -186,7 +252,7 @@ public void printCalculations(String pair, double bnbFeeValue, Iterator<Row> row
186252
}
187253

188254
log("Data for " + pair);
189-
log("#Orders (BUY+SELL): " + orders.size());
255+
log("#Trades (BUY+SELL): " + orders.size());
190256
log("Volume: " + roundedToSignificance(volume));
191257
log("Sub Total Profit: " + roundedToSignificance(cumProfit));
192258

@@ -200,7 +266,7 @@ public void printCalculations(String pair, double bnbFeeValue, Iterator<Row> row
200266
}
201267

202268
/**
203-
* @param candles to get the price from
269+
* @param candles to get the price from
204270
* @param timestamp of the price you want to know
205271
* @returns the closing price of the candle. -1 if no candle was found.
206272
* You can use {@link #loadHistoricalPrice(String, long)} if this function returns -1.

0 commit comments

Comments
 (0)