22
33import com .binance .api .client .BinanceApiClientFactory ;
44import com .binance .api .client .BinanceApiRestClient ;
5+ import com .binance .api .client .domain .market .Candlestick ;
56import com .binance .api .client .domain .market .CandlestickInterval ;
67import com .nubebuster .cryptoprofittracker .caching .CandleStickCollector ;
78import org .apache .poi .openxml4j .opc .OPCPackage ;
1415import java .io .FileWriter ;
1516import java .math .BigDecimal ;
1617import java .math .MathContext ;
18+ import java .rmi .UnexpectedException ;
1719import java .util .ArrayList ;
1820import java .util .Iterator ;
1921import java .util .List ;
2022
2123public class BinanceProfitTracker {
2224
25+ private static final CandlestickInterval CACHE_PRECISION = CandlestickInterval .FIVE_MINUTES ;
26+
2327 public static void main (String [] args ) {
2428 try {
2529 String pair = args [0 ];
@@ -83,7 +87,6 @@ public BinanceApiRestClient getBinanceClient() {
8387 }
8488
8589 public void printCalculations (String pair , double bnbFeeValue , Iterator <Row > rows ) throws Exception {
86-
8790 List <TradeOrder > orders = new ArrayList <TradeOrder >();
8891
8992 long oldest = Long .MAX_VALUE ;
@@ -111,9 +114,9 @@ public void printCalculations(String pair, double bnbFeeValue, Iterator<Row> row
111114 orders .add (new TradeOrder (pair , buy , price , amount , total , fee , feeCoin , time ));
112115 }
113116
114- //collect all candles from the transaction period to be able to convert at timestamps without querying.
115- candleStickCollector .getCandlesCollectWhenMissing (pair , oldest , newest ,
116- CandlestickInterval . FIFTEEN_MINUTES );
117+ // //collect all candles from the first to last transaction to be able to convert at timestamps without querying.
118+ // List<Candlestick> candles = candleStickCollector.getCandlesCollectWhenMissing(pair, oldest - CryptoProfitTrackerUtils.convertCandleStickIntervalToMs(CACHE_PRECISION) , newest + CryptoProfitTrackerUtils.convertCandleStickIntervalToMs(CACHE_PRECISION) ,
119+ // CACHE_PRECISION );
117120
118121 double cumProfit = 0 ;
119122 double amountInWallet = 0 ;
@@ -135,6 +138,9 @@ public void printCalculations(String pair, double bnbFeeValue, Iterator<Row> row
135138 } else if (order .getFeeCoin ().equals ("BNB" )) {
136139 accruedFees += order .getTotal () * bnbFeeValue ;
137140 } else {
141+ if (!pair .toLowerCase ().contains (order .getFeeCoin ().toLowerCase ()))
142+ throw new UnexpectedException ("Fee coin for " + pair + " was in " + order .getFeeCoin ()
143+ + ". This is not supported yet. Report this to the github repository." );
138144 amountInWallet -= order .getFee ();
139145 }
140146 }
@@ -151,30 +157,55 @@ public void printCalculations(String pair, double bnbFeeValue, Iterator<Row> row
151157 System .out .println ("\n Fees total: " + roundedToSignificance (accruedFees ));
152158
153159 System .out .println ("\n Total profit: " + Math .floor (cumProfit + walletValue - accruedFees ));
160+ }
154161
162+ /**
163+ * @param candles to get the price from
164+ * @param timestamp of the price you want to know
165+ * @returns the closing price of the candle. -1 if no candle was found.
166+ * You can use {@link #loadHistoricalPrice(String, long)} if this function returns -1.
167+ */
168+ private double getHistoricalPrice (List <Candlestick > candles , long timestamp ) {
169+ long startRounded = timestamp - (timestamp % CryptoProfitTrackerUtils .convertCandleStickIntervalToMs (CACHE_PRECISION ));
170+ for (Candlestick candle : candles ) {
171+ if (candle .getOpenTime () == startRounded ) return Double .parseDouble (candle .getClose ());
172+ }
173+ System .err .println ("Is there a candle missing in the candle stick data?" );
174+ return -1 ;
155175 }
156176
157- private double getHistoricalPrice (String ticker , long timestamp ) throws Exception {
158- return Double .parseDouble (candleStickCollector .getCandlesCollectWhenMissing (ticker , timestamp , timestamp
159- + CryptoProfitTrackerUtils .convertCandleStickIntervalToMs (CandlestickInterval .FIFTEEN_MINUTES ),
160- CandlestickInterval .FIFTEEN_MINUTES ).get (0 ).getClose ());
177+ /**
178+ * Use this function if {@link #getHistoricalPrice(List, long)} returns -1.
179+ *
180+ * @param ticker
181+ * @param timestamp
182+ * @return
183+ * @throws Exception
184+ */
185+ @ Deprecated
186+ private double loadHistoricalPrice (String ticker , long timestamp ) throws Exception {
187+ return Double .parseDouble (candleStickCollector .getCandlesCollectWhenMissing (ticker ,
188+ timestamp - CryptoProfitTrackerUtils .convertCandleStickIntervalToMs (CACHE_PRECISION ),
189+ timestamp ,
190+ CACHE_PRECISION ).get (0 ).getClose ());
161191 }
162192
163193 private double roundedToSignificance (double input ) {
164194 BigDecimal bd = new BigDecimal (input );
165195 return bd .round (new MathContext (8 )).doubleValue ();
166196 }
167197
168-
169- //Very slow HMMMMMM
170- // maybe just go with %
198+ /**
199+ * @deprecated this is slow and {@link #getHistoricalPrice(List, long)} should be used for a less precise, cached price.
200+ * Alternatively, you can use {@link #loadHistoricalPrice(String, long)} to load the price from the cache.
201+ *
202+ */
171203 @ Deprecated
172- private Double getPriceAtTime (String ticker , long timestamp ) {
204+ private Double queryPriceAtTime (String ticker , long timestamp ) {
173205 return Double .parseDouble (client .getCandlestickBars (ticker , CandlestickInterval .ONE_MINUTE , 1 , timestamp , timestamp + 60000 ).get (0 ).getHigh ());
174206 }
175207
176208 private Double getPrice (String ticker ) {
177209 return Double .parseDouble (client .getPrice (ticker ).getPrice ());
178210 }
179-
180211}
0 commit comments