From 0e624c95abb3f21dc849aae82164feb5b0a99abf Mon Sep 17 00:00:00 2001 From: Zack Urben Date: Tue, 14 Jan 2014 22:52:07 -0600 Subject: [PATCH] Converted floats to BigDecimals and more. Converted floats to BigDecimals for precision and to fix scientific notation problems. Updated GUI display of last activity and start time to human-readable dates. --- TODO.txt | 2 - changelog.txt | 5 + src/Dashboard.java | 24 ++-- src/Login.java | 4 +- src/Reinvestor.java | 170 +++++++++++++++++----------- src/zackurben/cex/data/Balance.java | 17 ++- src/zackurben/cex/data/Coin.java | 19 ++-- src/zackurben/cex/data/Order.java | 20 ++-- src/zackurben/cex/data/Ticker.java | 16 +-- 9 files changed, 174 insertions(+), 103 deletions(-) diff --git a/TODO.txt b/TODO.txt index 4178868..4e3aeab 100644 --- a/TODO.txt +++ b/TODO.txt @@ -1,3 +1 @@ Program TODO: - - Add program run-time to GUI version. - - Update the size of text boxes, in GUI version, due to MS Windows panel Sizing. diff --git a/changelog.txt b/changelog.txt index 0ba887d..f9254bb 100644 --- a/changelog.txt +++ b/changelog.txt @@ -13,3 +13,8 @@ - Added program runtime to Information Tab. - Minor GUI tweaks to fix the interface on Windows machines. - Code clean up. + +1.0.3 + - Converted floats to BigDecimals for precision + - Fixed bug where ReinvestorThread would crash due to floats being converted to scientific notation. + - Updated GUI Display of last activity and start time. diff --git a/src/Dashboard.java b/src/Dashboard.java index ef52bb5..e87a9ce 100644 --- a/src/Dashboard.java +++ b/src/Dashboard.java @@ -4,7 +4,7 @@ * under the Apache V2 License, which can be found at: gson/LICENSE.txt * * Dashboard.java - * Version : 1.0.2 + * Version : 1.0.3 * Author : Zack Urben * Contact : zackurben@gmail.com * Creation : 12/31/13 @@ -33,6 +33,8 @@ import java.awt.Font; import java.io.File; import java.io.FileNotFoundException; +import java.math.BigDecimal; +import java.math.RoundingMode; import java.util.Date; import java.util.Scanner; import javax.swing.JScrollPane; @@ -87,6 +89,8 @@ public class Dashboard { protected JTextPane TEXTPANE_CEX; protected JTextPane TEXTPANE_CRYPTSY; protected JScrollPane SCROLLPANE; + protected long NUM_START_TIME; + protected long NUM_LAST_ACTIVITY; protected Reinvestor user; /** @@ -463,13 +467,19 @@ private void loadSettings() { */ private void updateSettings() { this.user.BTC.active = CHECKBOX_BTC.isSelected(); - this.user.BTC.reserve = Float.valueOf(INPUT_RESERVE_BTC.getText()); - this.user.BTC.max = Float.valueOf(INPUT_MAX_BTC.getText()); - this.user.BTC.min = Float.valueOf(INPUT_MIN_BTC.getText()); + this.user.BTC.reserve = new BigDecimal(INPUT_RESERVE_BTC.getText()) + .setScale(8, RoundingMode.DOWN); + this.user.BTC.max = new BigDecimal(INPUT_MAX_BTC.getText()).setScale(8, + RoundingMode.DOWN); + this.user.BTC.min = new BigDecimal(INPUT_MIN_BTC.getText()).setScale(8, + RoundingMode.DOWN); this.user.NMC.active = CHECKBOX_NMC.isSelected(); - this.user.NMC.reserve = Float.valueOf(INPUT_RESERVE_NMC.getText()); - this.user.NMC.max = Float.valueOf(INPUT_MAX_NMC.getText()); - this.user.NMC.min = Float.valueOf(INPUT_MIN_NMC.getText()); + this.user.NMC.reserve = new BigDecimal(INPUT_RESERVE_NMC.getText()) + .setScale(8, RoundingMode.DOWN); + this.user.NMC.max = new BigDecimal(INPUT_MAX_NMC.getText()).setScale(8, + RoundingMode.DOWN); + this.user.NMC.min = new BigDecimal(INPUT_MIN_NMC.getText()).setScale(8, + RoundingMode.DOWN); } } diff --git a/src/Login.java b/src/Login.java index cdd2e53..14584c1 100644 --- a/src/Login.java +++ b/src/Login.java @@ -4,7 +4,7 @@ * under the Apache V2 License, which can be found at: gson/LICENSE.txt * * Login.java - * Version : 1.0.2 + * Version : 1.0.3 * Author : Zack Urben * Contact : zackurben@gmail.com * Creation : 12/31/13 @@ -87,7 +87,7 @@ private void initialize() { LABEL_VERSION.setBounds(312, 167, 47, 16); PANEL.add(LABEL_VERSION); - LABEL_VERSION_NUMBER = new JLabel("1.0.2"); + LABEL_VERSION_NUMBER = new JLabel("1.0.3"); LABEL_VERSION_NUMBER.setEnabled(false); LABEL_VERSION_NUMBER.setBounds(371, 167, 61, 16); PANEL.add(LABEL_VERSION_NUMBER); diff --git a/src/Reinvestor.java b/src/Reinvestor.java index 963bf17..6e05194 100644 --- a/src/Reinvestor.java +++ b/src/Reinvestor.java @@ -4,7 +4,7 @@ * under the Apache V2 License, which can be found at: gson/LICENSE.txt * * Reinvestor.java - * Version : 1.0.2 + * Version : 1.0.3 * Author : Zack Urben * Contact : zackurben@gmail.com * Creation : 12/31/13 @@ -22,12 +22,11 @@ import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; +import java.math.BigDecimal; import java.math.RoundingMode; import java.text.DecimalFormat; -import java.text.DecimalFormatSymbols; import java.util.ArrayList; import java.util.Date; -import java.util.Locale; import java.util.Scanner; import zackurben.cex.data.*; import zackurben.cex.data.Balance.Currency; @@ -40,11 +39,10 @@ public class Reinvestor extends CexAPI { protected int apiCalls; protected Balance balance; protected Coin BTC, NMC; - protected boolean done; protected InputThread input; protected ReinvestThread reinvest; protected Dashboard gui; - protected boolean debug = false; + protected boolean done, debug = false; /** * Reinvestor constructor for Terminal/bash/cmd mode. @@ -59,8 +57,10 @@ public Reinvestor(String user, String key, String secret) { this.startTime = System.currentTimeMillis(); this.lastTime = this.startTime; this.apiCalls = 0; - this.BTC = new Coin(true, 0f, 0f, 0f, "GHS/BTC"); - this.NMC = new Coin(true, 0f, 0f, 0f, "GHS/NMC"); + this.BTC = new Coin(true, BigDecimal.ZERO, BigDecimal.ZERO, + BigDecimal.ZERO, "GHS/BTC"); + this.NMC = new Coin(true, BigDecimal.ZERO, BigDecimal.ZERO, + BigDecimal.ZERO, "GHS/NMC"); this.done = false; this.input = new InputThread(this); this.gui = null; @@ -79,8 +79,10 @@ public Reinvestor(String user, String key, String secret, Dashboard input) { this.startTime = System.currentTimeMillis(); this.lastTime = this.startTime; this.apiCalls = 0; - this.BTC = new Coin(true, 0f, 0f, 0f, "GHS/BTC"); - this.NMC = new Coin(true, 0f, 0f, 0f, "GHS/NMC"); + this.BTC = new Coin(true, BigDecimal.ZERO, BigDecimal.ZERO, + BigDecimal.ZERO, "GHS/BTC"); + this.NMC = new Coin(true, BigDecimal.ZERO, BigDecimal.ZERO, + BigDecimal.ZERO, "GHS/NMC"); this.done = false; this.input = new InputThread(this); this.gui = input; @@ -91,7 +93,9 @@ public Reinvestor(String user, String key, String secret, Dashboard input) { this.gui.DISPLAY_CANCELED.setText("0"); this.gui.DISPLAY_ORDERS.setText("0"); this.gui.DISPLAY_PENDING.setText("0"); - this.gui.DISPLAY_START_TIME.setText(String.valueOf(this.startTime)); + this.gui.DISPLAY_START_TIME.setText(new Date(this.startTime) + .toString()); + this.gui.NUM_START_TIME = this.startTime; this.gui.DISPLAY_STATUS.setText("Idle"); this.gui.DISPLAY_USERNAME.setText(user); } else { @@ -185,12 +189,9 @@ public void log(String file, String input) { * @return String representation of the float, up to 8 decimal places, * rounded down. */ - public String formatNumber(float input) { - DecimalFormat format = new DecimalFormat("###0.00000000"); - format.setRoundingMode(RoundingMode.DOWN); - format.setDecimalFormatSymbols(DecimalFormatSymbols - .getInstance(Locale.US)); - return format.format(input); + public String formatNumber(BigDecimal input) { + input = input.setScale(8, RoundingMode.DOWN); + return input.toPlainString(); } /** @@ -208,10 +209,10 @@ public String formatBalance(String input) { + formatNumber(balance.GHS.available) + " " + formatNumber(balance.GHS.orders) + "\nIXC " + formatNumber(balance.IXC.available) + " " - + formatNumber(balance.IXC.orders) + "\nDVC " - + formatNumber(balance.DVC.available) + " " - + formatNumber(balance.DVC.orders) + "\nNMC " - + formatNumber(balance.NMC.available) + " " + // + formatNumber(balance.IXC.orders) // not available for trade + + "\nDVC " + formatNumber(balance.DVC.available) + " " + // + formatNumber(balance.DVC.orders) // not available for trade + + "\nNMC " + formatNumber(balance.NMC.available) + " " + formatNumber(balance.NMC.orders) + "\n"; } @@ -319,7 +320,9 @@ public String execute(String function, String parameters[]) { if (this.gui != null) { this.gui.DISPLAY_API_CALLS.setText(String.valueOf(this.apiCalls)); long temp = System.currentTimeMillis(); - this.gui.DISPLAY_LAST_ACTIVITY.setText(String.valueOf(temp)); + this.gui.DISPLAY_LAST_ACTIVITY.setText(new Date(temp) + .toString()); + this.gui.NUM_LAST_ACTIVITY = temp; this.gui.DISPLAY_DURATION.setText(this.formatDuration(temp)); } @@ -347,13 +350,13 @@ public void loadSettings() { } this.BTC.active = Boolean.valueOf(temp[3]); - this.BTC.reserve = Float.valueOf(temp[4]); - this.BTC.max = Float.valueOf(temp[5]); - this.BTC.min = Float.valueOf(temp[6]); + this.BTC.reserve = BigDecimal.valueOf(Double.valueOf(temp[4])); + this.BTC.max = BigDecimal.valueOf(Double.valueOf(temp[5])); + this.BTC.min = BigDecimal.valueOf(Double.valueOf(temp[6])); this.NMC.active = Boolean.valueOf(temp[7]); - this.NMC.reserve = Float.valueOf(temp[8]); - this.NMC.max = Float.valueOf(temp[9]); - this.NMC.min = Float.valueOf(temp[10]); + this.NMC.reserve = BigDecimal.valueOf(Double.valueOf(temp[8])); + this.NMC.max = BigDecimal.valueOf(Double.valueOf(temp[9])); + this.NMC.min = BigDecimal.valueOf(Double.valueOf(temp[10])); this.out("Settings loaded successfully!"); } catch (FileNotFoundException e) { this.out("Error 0xB."); @@ -373,10 +376,12 @@ public void saveSettings() { "settings.txt", false))); String temp = this.username + "," + this.apiKey + "," + this.apiSecret + "," + this.BTC.active + "," - + this.BTC.reserve + "," + this.BTC.max + "," - + this.BTC.min + "," + this.NMC.active + "," - + this.NMC.reserve + "," + this.NMC.max + "," - + this.NMC.min; + + this.BTC.reserve.toPlainString() + "," + + this.BTC.max.toPlainString() + "," + + this.BTC.min.toPlainString() + "," + this.NMC.active + + "," + this.NMC.reserve.toPlainString() + "," + + this.NMC.max.toPlainString() + "," + + this.NMC.min.toPlainString(); write.write(temp); this.out("Settings saved successfully!"); } catch (IOException e) { @@ -542,11 +547,13 @@ public void run() { // active, balance != null, reserve < available // active, pending trade_btc = ((this.user.BTC.active) - && (this.user.balance != null) && (this.user.BTC.reserve < this.user.balance.BTC.available)) + && (this.user.balance != null) && (this.user.BTC.reserve + .compareTo(this.user.balance.BTC.available) <= -1)) || ((this.user.BTC.active) && (!this.user.pending .isEmpty())); trade_nmc = ((this.user.NMC.active) - && (this.user.balance != null) && (this.user.NMC.reserve < this.user.balance.NMC.available)) + && (this.user.balance != null) && (this.user.NMC.reserve + .compareTo(this.user.balance.NMC.available) <= -1)) || ((this.user.NMC.active) && (!this.user.pending .isEmpty())); @@ -563,20 +570,38 @@ public void run() { this.analyze(this.user.balance.NMC, this.user.NMC); } } else { + if (this.user.debug) { + this.user + .out("[DBG] Waiting, insufficient funds to initiate new positions."); + } + // wait till next call, no trades available; remove due // to spam? // out("Reinvestor: Waiting, insufficient funds to initiate new positions."); } } catch (NullPointerException e) { // error with api call + if (this.user.debug) { + e.printStackTrace(); + } + this.user.nonce = Integer.valueOf((int) (System .currentTimeMillis() / 1000)); out("Error 0x1: " + this.user.balance.toString()); log("error", "Error 0x1:\n" + this.user.balance.toString()); } finally { try { + if (this.user.debug) { + this.user.out("[DBG] Sleeping Reinvestor Thread."); + } + Thread.sleep(30000); } catch (InterruptedException e) { + if (this.user.debug) { + this.user + .out("[DBG] Sleeping Reinvestor Thread was interrupted."); + } + // Reinvestment thread is stopped; Remove output, due to // spam. // out("Error 0x2."); @@ -600,8 +625,12 @@ public void analyze(Currency currency, Coin coin) { long temp = System.currentTimeMillis(); if (this.user.debug) { - this.user.out("[DBG] Analyzing the pending orders..! (" - + this.user.pending.size() + ", " + temp + ")"); + this.user + .out("[DBG] Analyzing the pending orders..! (Pending: " + + this.user.pending.size() + + ", " + + temp + + ")"); } for (int a = 0; a < this.user.pending.size(); a++) { @@ -610,8 +639,8 @@ public void analyze(Currency currency, Coin coin) { if (this.user.debug) { this.user - .out("[DBG] Trying to cancel the pending order..!\n" - + tempOrder.toString()); + .out("[DBG] Trying to cancel the pending order..!\n (Order: " + + tempOrder.toString() + ")"); } boolean canceled = Boolean.valueOf(this.user.execute( @@ -619,7 +648,7 @@ public void analyze(Currency currency, Coin coin) { new String[] { String.valueOf(tempOrder.id) })); if (this.user.debug) { - this.user.out("[DBG] Canceled: " + canceled); + this.user.out("[DBG] Canceled Status: " + canceled); } if (canceled) { @@ -628,9 +657,18 @@ public void analyze(Currency currency, Coin coin) { + tempOrder.toString()); out("Reinvestor: Canceled pending order (ID: " + tempOrder.id + ", Terminated: " - + formatNumber(tempOrder.pending) + " GHS " - + tempOrder.price + ")"); + + tempOrder.pending.toPlainString() + + " GHS " + tempOrder.price.toPlainString() + + ")"); this.user.pending.remove(a); + + // update gui display + if (this.user.gui != null) { + this.user.gui.DISPLAY_CANCELED + .setText(String.valueOf(Integer + .parseInt(this.user.gui.DISPLAY_CANCELED + .getText()) + 1)); + } } else { // error canceling order, completed already if (this.user.debug) { @@ -641,25 +679,25 @@ public void analyze(Currency currency, Coin coin) { log("buy", "Pending order completed:\n" + tempOrder.toString()); - out("Reinvestor: Purchase order complete; (ID: " + out("Reinvestor: Pending purchase order complete. (ID: " + tempOrder.id + ", Cost: " + formatNumber(tempOrder.amount - * tempOrder.price) + ")"); + .multiply(tempOrder.price)) + ")"); this.user.pending.remove(a); - } - // update gui display - if (this.user.gui != null) { - this.user.gui.DISPLAY_CANCELED - .setText(String.valueOf(Integer - .parseInt(this.user.gui.DISPLAY_CANCELED - .getText()) + 1)); + // update gui display + if (this.user.gui != null) { + this.user.gui.DISPLAY_CANCELED + .setText(String.valueOf(Integer + .parseInt(this.user.gui.DISPLAY_ORDERS + .getText()) + 1)); + } } } else { if (this.user.debug) { - this.user.out("[DBG] Pending orders: (" - + this.user.pending.toString() + ")"); + this.user.out("[DBG] Pending orders: " + + this.user.pending.toString()); } } } @@ -681,28 +719,31 @@ public void analyze(Currency currency, Coin coin) { */ // Make purchases - if (currency.available > coin.reserve) { + if (currency.available.compareTo(coin.reserve) == 1) { Ticker price = new Gson().fromJson(this.user.execute("ticker", new String[] { coin.ticker }), Ticker.class); // if price range is within user specified limits: purchase - if (((coin.max == 0) || (coin.max >= price.last)) - && ((coin.min == 0) || (price.last >= coin.min))) { + if (((coin.max.compareTo(BigDecimal.ZERO) == 0) || (coin.max + .compareTo(price.last) == 1)) + && ((coin.min.compareTo(BigDecimal.ZERO) == 0) || (price.last + .compareTo(coin.min)) == 1)) { // calculate amount to buy - float calc = ((currency.available - coin.reserve) / price.last); - float amt = Float.valueOf(formatNumber(calc)); - if (amt > 0.00000001) { + BigDecimal amt = (currency.available.subtract(coin.reserve)) + .divide(price.last, 8, RoundingMode.DOWN); + + if (amt.compareTo(new BigDecimal(0.00000001)) == 1) { Order order = new Gson().fromJson( this.user.execute( "place_order", new String[] { coin.ticker, "buy", - String.valueOf(amt), - String.valueOf(price.last) }), + amt.toPlainString(), + price.last.toPlainString() }), Order.class); // check if order contains pending values if (order.error == "") { - if (order.pending == 0) { + if (order.pending.compareTo(BigDecimal.ZERO) == 0) { log("buy", "Order complete:\n" + order.toString()); out("Reinvestor: Purchased " @@ -713,7 +754,7 @@ public void analyze(Currency currency, Coin coin) { + coin.ticker + " (Cost: " + formatNumber(order.price - * order.amount) + ")"); + .multiply(order.amount)) + ")"); // update gui display if (this.user.gui != null) { @@ -759,10 +800,11 @@ public void analyze(Currency currency, Coin coin) { } else { out("Reinvestor: The current price of a " + coin.ticker + ", is outside your specified limits (Price: " - + price.last + ", Range: " + coin.min + "-" - + coin.max + ")."); + + price.last.toPlainString() + ", Range: " + + coin.min.toPlainString() + "-" + + coin.max.toPlainString() + ")."); } - } else if (currency.available != coin.reserve) { + } else if (currency.available.compareTo(coin.reserve) != 0) { out("Reinvestor: The coins available, is less than the allocated reserve limit (Coins: " + this.user.formatNumber(currency.available) + ", Reserve: " diff --git a/src/zackurben/cex/data/Balance.java b/src/zackurben/cex/data/Balance.java index 9f0cf2a..73db708 100644 --- a/src/zackurben/cex/data/Balance.java +++ b/src/zackurben/cex/data/Balance.java @@ -4,7 +4,7 @@ * under the Apache V2 License, which can be found at: gson/LICENSE.txt * * Balance.java - * Version : 1.0.2 + * Version : 1.0.3 * Author : Zack Urben * Contact : zackurben@gmail.com * Creation : 12/31/13 @@ -20,6 +20,8 @@ package zackurben.cex.data; +import java.math.BigDecimal; + public class Balance { public long timestamp; public String username; @@ -49,14 +51,21 @@ public String toString() { * objects. */ public class Currency { - public float available; - public float orders; + public BigDecimal available = new BigDecimal("0.00000000"); + public BigDecimal orders = new BigDecimal("0.00000000"); /** * Overide the default toString method to give basic object data dump. */ public String toString() { - return "[" + this.available + ":" + this.orders + "]"; + String output = "[" + this.available.toPlainString(); + + if (this.orders != null) { + output += ":" + this.orders.toPlainString(); + } + output += "]"; + + return output; } } } diff --git a/src/zackurben/cex/data/Coin.java b/src/zackurben/cex/data/Coin.java index 51508fa..59d67d4 100644 --- a/src/zackurben/cex/data/Coin.java +++ b/src/zackurben/cex/data/Coin.java @@ -4,7 +4,7 @@ * under the Apache V2 License, which can be found at: gson/LICENSE.txt * * Coin.java - * Version : 1.0.0 + * Version : 1.0.3 * Author : Zack Urben * Contact : zackurben@gmail.com * Creation : 12/31/13 @@ -20,11 +20,13 @@ package zackurben.cex.data; +import java.math.BigDecimal; + public class Coin { public boolean active; - public float reserve; - public float max; - public float min; + public BigDecimal reserve = new BigDecimal("0.00000000"); + public BigDecimal max = new BigDecimal("0.00000000"); + public BigDecimal min = new BigDecimal("0.00000000"); public String ticker; /** @@ -37,8 +39,8 @@ public class Coin { * @param min (Float) - The minimum amount allowed to pay for 1 GHS/COIN * @param ticker (String) - The pair ticker for Cex.io */ - public Coin(Boolean active, float reserve, float max, float min, - String ticker) { + public Coin(Boolean active, BigDecimal reserve, BigDecimal max, + BigDecimal min, String ticker) { this.active = active; this.reserve = reserve; this.max = max; @@ -50,7 +52,8 @@ public Coin(Boolean active, float reserve, float max, float min, * Overide the default toString method to give basic object data dump. */ public String toString() { - return "{" + this.active + ":" + this.reserve + ":" + this.max + ":" - + this.min + ":" + this.ticker + "}"; + return "{" + this.active + ":" + this.reserve.toPlainString() + ":" + + this.max.toPlainString() + ":" + this.min.toPlainString() + + ":" + this.ticker + "}"; } } diff --git a/src/zackurben/cex/data/Order.java b/src/zackurben/cex/data/Order.java index 5392636..a7530f8 100644 --- a/src/zackurben/cex/data/Order.java +++ b/src/zackurben/cex/data/Order.java @@ -4,7 +4,7 @@ * under the Apache V2 License, which can be found at: gson/LICENSE.txt * * Order.java - * Version : 1.0.2 + * Version : 1.0.3 * Author : Zack Urben * Contact : zackurben@gmail.com * Creation : 12/31/13 @@ -20,16 +20,16 @@ package zackurben.cex.data; +import java.math.BigDecimal; import java.math.RoundingMode; -import java.text.DecimalFormat; public class Order { public int id; public long time; - public float pending; - public float amount; + public BigDecimal pending = new BigDecimal("0.00000000"); + public BigDecimal amount = new BigDecimal("0.00000000"); public String type; - public float price; + public BigDecimal price = new BigDecimal("0.00000000"); public String error = ""; /** @@ -39,10 +39,12 @@ public class Order { * @return String representation of the float, up to 8 decimal places, * rounded down. */ - public String formatNumber(float input) { - DecimalFormat df = new DecimalFormat("###0.00000000"); - df.setRoundingMode(RoundingMode.DOWN); - return df.format(input); + public String formatNumber(BigDecimal input) { + // DecimalFormat df = new DecimalFormat("###0.00000000"); + // df.setRoundingMode(RoundingMode.DOWN); + // return df.format(input); + input = input.setScale(8, RoundingMode.DOWN); + return input.toString(); } /** diff --git a/src/zackurben/cex/data/Ticker.java b/src/zackurben/cex/data/Ticker.java index b56d9de..cdcb70f 100644 --- a/src/zackurben/cex/data/Ticker.java +++ b/src/zackurben/cex/data/Ticker.java @@ -4,7 +4,7 @@ * under the Apache V2 License, which can be found at: gson/LICENSE.txt * * Ticker.java - * Version : 1.0.0 + * Version : 1.0.3 * Author : Zack Urben * Contact : zackurben@gmail.com * Creation : 12/31/13 @@ -20,12 +20,14 @@ package zackurben.cex.data; +import java.math.BigDecimal; + public class Ticker { public long timestamp; - public float low; - public float high; - public float last; - public float volume; - public float bid; - public float ask; + public BigDecimal low = new BigDecimal("0.00000000"); + public BigDecimal high = new BigDecimal("0.00000000"); + public BigDecimal last = new BigDecimal("0.00000000"); + public BigDecimal volume = new BigDecimal("0.00000000"); + public BigDecimal bid = new BigDecimal("0.00000000"); + public BigDecimal ask = new BigDecimal("0.00000000"); }