show sum volume and amount in market view

This commit is contained in:
woodser 2025-05-20 15:14:47 -04:00
parent 11de7f540b
commit 11b0fab728
No known key found for this signature in database
GPG key ID: 55A10DD48ADEE5EF
4 changed files with 74 additions and 8 deletions

View file

@ -51,6 +51,7 @@ import org.bitcoinj.utils.MonetaryFormat;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.Collection;
import java.util.Locale;
public class VolumeUtil {
@ -187,4 +188,35 @@ public class VolumeUtil {
private static MonetaryFormat getMonetaryFormat(String currencyCode) {
return CurrencyUtil.isVolumeRoundedToNearestUnit(currencyCode) ? VOLUME_FORMAT_UNIT : VOLUME_FORMAT_PRECISE;
}
public static Volume sum(Collection<Volume> volumes) {
if (volumes == null || volumes.isEmpty()) {
return null;
}
Volume sum = null;
for (Volume volume : volumes) {
if (sum == null) {
sum = volume;
} else {
if (!sum.getCurrencyCode().equals(volume.getCurrencyCode())) {
throw new IllegalArgumentException("Cannot sum volumes with different currencies");
}
sum = add(sum, volume);
}
}
return sum;
}
public static Volume add(Volume volume1, Volume volume2) {
if (volume1 == null) return volume2;
if (volume2 == null) return volume1;
if (!volume1.getCurrencyCode().equals(volume2.getCurrencyCode())) {
throw new IllegalArgumentException("Cannot add volumes with different currencies");
}
if (volume1.getMonetary() instanceof CryptoMoney) {
return new Volume(((CryptoMoney) volume1.getMonetary()).add((CryptoMoney) volume2.getMonetary()));
} else {
return new Volume(((TraditionalMoney) volume1.getMonetary()).add((TraditionalMoney) volume2.getMonetary()));
}
}
}

View file

@ -407,8 +407,10 @@ shared.notSigned.noNeedAlts=Cryptocurrency accounts do not feature signing or ag
offerbook.nrOffers=No. of offers: {0}
offerbook.volume={0} (min - max)
offerbook.volumeTotal={0} ({1})
offerbook.deposit=Deposit XMR (%)
offerbook.deposit.help=Deposit paid by each trader to guarantee the trade. Will be returned when the trade is completed.
offerbook.XMRTotal=XMR ({0})
offerbook.createNewOffer=Create offer to {0} {1}
offerbook.createOfferDisabled.tooltip=You can only create one offer at a time

View file

@ -95,7 +95,10 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
private AnchorPane chartPane;
private AutocompleteComboBox<CurrencyListItem> currencyComboBox;
private Subscription tradeCurrencySubscriber;
private final StringProperty volumeColumnLabel = new SimpleStringProperty();
private final StringProperty volumeSellColumnLabel = new SimpleStringProperty();
private final StringProperty volumeBuyColumnLabel = new SimpleStringProperty();
private final StringProperty amountSellColumnLabel = new SimpleStringProperty();
private final StringProperty amountBuyColumnLabel = new SimpleStringProperty();
private final StringProperty priceColumnLabel = new SimpleStringProperty();
private AutoTooltipButton sellButton;
private AutoTooltipButton buyButton;
@ -201,7 +204,6 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
tradeCurrencySubscriber = EasyBind.subscribe(model.selectedTradeCurrencyProperty,
tradeCurrency -> {
String code = tradeCurrency.getCode();
volumeColumnLabel.set(Res.get("offerbook.volume", code));
xAxis.setTickLabelFormatter(new StringConverter<>() {
final int cryptoPrecision = 3;
final DecimalFormat df = new DecimalFormat(",###");
@ -351,6 +353,11 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
}
private synchronized void updateChartData() {
volumeSellColumnLabel.set(Res.get("offerbook.volumeTotal", model.getCurrencyCode(), VolumeUtil.formatVolume(model.getTotalVolume(OfferDirection.SELL))));
volumeBuyColumnLabel.set(Res.get("offerbook.volumeTotal", model.getCurrencyCode(), VolumeUtil.formatVolume(model.getTotalVolume(OfferDirection.BUY))));
amountSellColumnLabel.set(Res.get("offerbook.XMRTotal", "" + model.getTotalAmount(OfferDirection.SELL)));
amountBuyColumnLabel.set(Res.get("offerbook.XMRTotal", "" + model.getTotalAmount(OfferDirection.BUY)));
seriesBuy.getData().clear();
seriesSell.getData().clear();
areaChart.getData().clear();
@ -491,11 +498,13 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
}
});
boolean isSellTable = model.isSellOffer(direction);
// volume
TableColumn<OfferListItem, OfferListItem> volumeColumn = new TableColumn<>();
volumeColumn.setMinWidth(115);
volumeColumn.setSortable(false);
volumeColumn.textProperty().bind(volumeColumnLabel);
volumeColumn.textProperty().bind(isSellTable ? volumeSellColumnLabel : volumeBuyColumnLabel);
volumeColumn.getStyleClass().addAll("number-column");
volumeColumn.setCellValueFactory((offer) -> new ReadOnlyObjectWrapper<>(offer.getValue()));
volumeColumn.setCellFactory(
@ -553,7 +562,8 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
});
// amount
TableColumn<OfferListItem, OfferListItem> amountColumn = new AutoTooltipTableColumn<>(Res.get("shared.XMRMinMax"));
TableColumn<OfferListItem, OfferListItem> amountColumn = new TableColumn<>();
amountColumn.textProperty().bind(isSellTable ? amountSellColumnLabel : amountBuyColumnLabel);
amountColumn.setMinWidth(115);
amountColumn.setSortable(false);
amountColumn.getStyleClass().add("number-column");
@ -577,10 +587,8 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
}
});
boolean isSellOffer = model.isSellOffer(direction);
// trader avatar
TableColumn<OfferListItem, OfferListItem> avatarColumn = new AutoTooltipTableColumn<>(isSellOffer ?
TableColumn<OfferListItem, OfferListItem> avatarColumn = new AutoTooltipTableColumn<>(isSellTable ?
Res.get("shared.sellerUpperCase") : Res.get("shared.buyerUpperCase")) {
{
setMinWidth(80);
@ -645,7 +653,7 @@ public class OfferBookChartView extends ActivatableViewAndModel<VBox, OfferBookC
AutoTooltipButton button = new AutoTooltipButton();
button.setContentDisplay(ContentDisplay.RIGHT);
button.setGraphicTextGap(10);
button.updateText(isSellOffer ? Res.get("market.offerBook.buy") : Res.get("market.offerBook.sell"));
button.updateText(isSellTable ? Res.get("market.offerBook.buy") : Res.get("market.offerBook.sell"));
button.setMinHeight(32);
button.setOnAction(e -> model.goToOfferView(direction));

View file

@ -26,6 +26,7 @@ import haveno.core.locale.CurrencyUtil;
import haveno.core.locale.GlobalSettings;
import haveno.core.locale.TradeCurrency;
import haveno.core.monetary.Price;
import haveno.core.monetary.Volume;
import haveno.core.offer.Offer;
import haveno.core.offer.OfferDirection;
import haveno.core.offer.OpenOfferManager;
@ -215,6 +216,29 @@ class OfferBookChartViewModel extends ActivatableViewModel {
return direction == OfferDirection.SELL;
}
public double getTotalAmount(OfferDirection direction) {
synchronized (offerBookListItems) {
return offerBookListItems.stream()
.map(OfferBookListItem::getOffer)
.filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode())
&& e.getDirection().equals(direction))
.mapToDouble(item -> HavenoUtils.atomicUnitsToXmr(item.getAmount()))
.sum();
}
}
public Volume getTotalVolume(OfferDirection direction) {
synchronized (offerBookListItems) {
List<Volume> volumes = offerBookListItems.stream()
.map(OfferBookListItem::getOffer)
.filter(e -> e.getCurrencyCode().equals(selectedTradeCurrencyProperty.get().getCode())
&& e.getDirection().equals(direction))
.map(Offer::getVolume)
.collect(Collectors.toList());
return VolumeUtil.sum(volumes);
}
}
public boolean isMyOffer(Offer offer) {
return openOfferManager.isMyOffer(offer);
}