use list instead of set for trade statistics due to jfx bug

This commit is contained in:
woodser 2025-12-07 14:27:27 -05:00
parent 4686aba80f
commit c31dbd7697
No known key found for this signature in database
GPG key ID: 55A10DD48ADEE5EF
11 changed files with 35 additions and 36 deletions

View file

@ -337,7 +337,7 @@ public class CoreApi {
}
public List<TradeStatistics3> getTradeStatistics() {
return new ArrayList<>(tradeStatisticsManager.getObservableTradeStatisticsSet());
return new ArrayList<>(tradeStatisticsManager.getObservableTradeStatisticsList());
}
public int getNumConfirmationsForMostRecentTransaction(String addressString) {

View file

@ -62,7 +62,7 @@ public class DisputeAgentSelection {
DisputeAgentManager<T> disputeAgentManager,
Set<NodeAddress> excludedDisputeAgents) {
// We take last 100 entries from trade statistics
List<TradeStatistics3> list = new ArrayList<>(tradeStatisticsManager.getObservableTradeStatisticsSet());
List<TradeStatistics3> list = new ArrayList<>(tradeStatisticsManager.getObservableTradeStatisticsList());
list.sort(Comparator.comparing(TradeStatistics3::getDateAsLong));
Collections.reverse(list);
if (!list.isEmpty()) {

View file

@ -54,7 +54,6 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.CancellationException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
@ -346,10 +345,10 @@ public class PriceFeedService {
return new Date(epochInMillisAtLastRequest);
}
public void applyLatestHavenoMarketPrice(Set<TradeStatistics3> tradeStatisticsSet) {
public void applyLatestHavenoMarketPrice(List<TradeStatistics3> tradeStatisticsList) {
// takes about 10 ms for 5000 items
Map<String, List<TradeStatistics3>> mapByCurrencyCode = new HashMap<>();
tradeStatisticsSet.forEach(e -> {
tradeStatisticsList.forEach(e -> {
List<TradeStatistics3> list;
String currencyCode = e.getCurrency();
if (mapByCurrencyCode.containsKey(currencyCode)) {

View file

@ -43,7 +43,7 @@ import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javafx.collections.FXCollections;
import javafx.collections.ObservableSet;
import javafx.collections.ObservableList;
import javax.annotation.Nullable;
import lombok.extern.slf4j.Slf4j;
@ -55,7 +55,7 @@ public class TradeStatisticsManager {
private final TradeStatistics3StorageService tradeStatistics3StorageService;
private final File storageDir;
private final boolean dumpStatistics;
private final ObservableSet<TradeStatistics3> observableTradeStatisticsSet = FXCollections.observableSet();
private final ObservableList<TradeStatistics3> observableTradeStatisticsList = FXCollections.observableArrayList();
private JsonFileManager jsonFileManager;
public static final int PUBLISH_STATS_RANDOM_DELAY_HOURS = 24;
@ -89,9 +89,9 @@ public class TradeStatisticsManager {
if (!tradeStatistics.isValid()) {
return;
}
synchronized (observableTradeStatisticsSet) {
observableTradeStatisticsSet.add(tradeStatistics);
priceFeedService.applyLatestHavenoMarketPrice(observableTradeStatisticsSet);
synchronized (observableTradeStatisticsList) {
observableTradeStatisticsList.add(tradeStatistics);
priceFeedService.applyLatestHavenoMarketPrice(observableTradeStatisticsList);
}
maybeDumpStatistics();
}
@ -107,9 +107,9 @@ public class TradeStatisticsManager {
// remove duplicates in early trade stats due to bugs
removeDuplicateStats(set);
synchronized (observableTradeStatisticsSet) {
observableTradeStatisticsSet.addAll(set);
priceFeedService.applyLatestHavenoMarketPrice(observableTradeStatisticsSet);
synchronized (observableTradeStatisticsList) {
observableTradeStatisticsList.addAll(set);
priceFeedService.applyLatestHavenoMarketPrice(observableTradeStatisticsList);
}
maybeDumpStatistics();
}
@ -195,8 +195,8 @@ public class TradeStatisticsManager {
return isWithinFuzzedHours && isWithinFuzzedAmount;
}
public ObservableSet<TradeStatistics3> getObservableTradeStatisticsSet() {
return observableTradeStatisticsSet;
public ObservableList<TradeStatistics3> getObservableTradeStatisticsList() {
return observableTradeStatisticsList;
}
private void maybeDumpStatistics() {
@ -220,7 +220,7 @@ public class TradeStatisticsManager {
jsonFileManager.writeToDiscThreaded(JsonUtil.objectToJson(cryptoCurrencyList), "crypto_currency_list");
Instant yearAgo = Instant.ofEpochSecond(Instant.now().getEpochSecond() - TimeUnit.DAYS.toSeconds(365));
Set<String> activeCurrencies = observableTradeStatisticsSet.stream()
Set<String> activeCurrencies = observableTradeStatisticsList.stream()
.filter(e -> e.getDate().toInstant().isAfter(yearAgo))
.map(p -> p.getCurrency())
.collect(Collectors.toSet());
@ -238,7 +238,7 @@ public class TradeStatisticsManager {
jsonFileManager.writeToDiscThreaded(JsonUtil.objectToJson(activeCryptoCurrencyList), "active_crypto_currency_list");
}
List<TradeStatisticsForJson> list = observableTradeStatisticsSet.stream()
List<TradeStatisticsForJson> list = observableTradeStatisticsList.stream()
.map(TradeStatisticsForJson::new)
.sorted((o1, o2) -> (Long.compare(o2.tradeDate, o1.tradeDate)))
.collect(Collectors.toList());

View file

@ -42,7 +42,7 @@ public class AveragePriceUtil {
int days) {
double percentToTrim = Math.max(0, Math.min(49, preferences.getBsqAverageTrimThreshold() * 100));
Date pastXDays = getPastDate(days);
List<TradeStatistics3> bsqAllTradePastXDays = tradeStatisticsManager.getObservableTradeStatisticsSet().stream()
List<TradeStatistics3> bsqAllTradePastXDays = tradeStatisticsManager.getObservableTradeStatisticsList().stream()
.filter(e -> e.getCurrency().equals("BSQ"))
.filter(e -> e.getDate().after(pastXDays))
.collect(Collectors.toList());
@ -50,7 +50,7 @@ public class AveragePriceUtil {
removeOutliers(bsqAllTradePastXDays, percentToTrim) :
bsqAllTradePastXDays;
List<TradeStatistics3> usdAllTradePastXDays = tradeStatisticsManager.getObservableTradeStatisticsSet().stream()
List<TradeStatistics3> usdAllTradePastXDays = tradeStatisticsManager.getObservableTradeStatisticsList().stream()
.filter(e -> e.getCurrency().equals("USD"))
.filter(e -> e.getDate().after(pastXDays))
.collect(Collectors.toList());

View file

@ -59,7 +59,7 @@ public class ChartCalculations {
// Async
///////////////////////////////////////////////////////////////////////////////////////////
static CompletableFuture<Map<TradesChartsViewModel.TickUnit, Map<Long, Long>>> getUsdAveragePriceMapsPerTickUnit(Set<TradeStatistics3> tradeStatisticsSet) {
static CompletableFuture<Map<TradesChartsViewModel.TickUnit, Map<Long, Long>>> getUsdAveragePriceMapsPerTickUnit(List<TradeStatistics3> tradeStatisticsList) {
return CompletableFuture.supplyAsync(() -> {
Map<TradesChartsViewModel.TickUnit, Map<Long, Long>> usdAveragePriceMapsPerTickUnit = new HashMap<>();
Map<TradesChartsViewModel.TickUnit, Map<Long, List<TradeStatistics3>>> dateMapsPerTickUnit = new HashMap<>();
@ -67,7 +67,7 @@ public class ChartCalculations {
dateMapsPerTickUnit.put(tick, new HashMap<>());
}
tradeStatisticsSet.stream()
tradeStatisticsList.stream()
.filter(e -> e.getCurrency().equals("USD"))
.forEach(tradeStatistics -> {
for (TradesChartsViewModel.TickUnit tick : TradesChartsViewModel.TickUnit.values()) {
@ -80,18 +80,18 @@ public class ChartCalculations {
dateMapsPerTickUnit.forEach((tick, map) -> {
HashMap<Long, Long> priceMap = new HashMap<>();
map.forEach((date, tradeStatisticsList) -> priceMap.put(date, getAverageTraditionalPrice(tradeStatisticsList)));
map.forEach((date, tradeStatistics) -> priceMap.put(date, getAverageTraditionalPrice(tradeStatistics)));
usdAveragePriceMapsPerTickUnit.put(tick, priceMap);
});
return usdAveragePriceMapsPerTickUnit;
});
}
static CompletableFuture<List<TradeStatistics3>> getTradeStatisticsForCurrency(Set<TradeStatistics3> tradeStatisticsSet,
static CompletableFuture<List<TradeStatistics3>> getTradeStatisticsForCurrency(List<TradeStatistics3> tradeStatisticsList,
String currencyCode,
boolean showAllTradeCurrencies) {
return CompletableFuture.supplyAsync(() -> {
return tradeStatisticsSet.stream()
return tradeStatisticsList.stream()
.filter(e -> showAllTradeCurrencies || e.getCurrency().equals(currencyCode))
.collect(Collectors.toList());
});

View file

@ -41,8 +41,8 @@ import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.SetChangeListener;
import javafx.scene.chart.XYChart;
import javafx.util.Pair;
@ -79,7 +79,7 @@ class TradesChartsViewModel extends ActivatableViewModel {
private final PriceFeedService priceFeedService;
private final Navigation navigation;
private final SetChangeListener<TradeStatistics3> setChangeListener;
private final ListChangeListener<TradeStatistics3> listChangeListener;
final ObjectProperty<TradeCurrency> selectedTradeCurrencyProperty = new SimpleObjectProperty<>();
final BooleanProperty showAllTradeCurrenciesProperty = new SimpleBooleanProperty(false);
private final CurrencyList currencyListItems;
@ -109,7 +109,7 @@ class TradesChartsViewModel extends ActivatableViewModel {
this.priceFeedService = priceFeedService;
this.navigation = navigation;
setChangeListener = change -> {
listChangeListener = change -> {
applyAsyncTradeStatisticsForCurrency(getCurrencyCode())
.whenComplete((result, throwable) -> {
if (deactivateCalled) {
@ -141,7 +141,7 @@ class TradesChartsViewModel extends ActivatableViewModel {
long ts = System.currentTimeMillis();
deactivateCalled = false;
tradeStatisticsManager.getObservableTradeStatisticsSet().addListener(setChangeListener);
tradeStatisticsManager.getObservableTradeStatisticsList().addListener(listChangeListener);
if (!fillTradeCurrenciesOnActivateCalled) {
fillTradeCurrencies();
fillTradeCurrenciesOnActivateCalled = true;
@ -179,7 +179,7 @@ class TradesChartsViewModel extends ActivatableViewModel {
@Override
protected void deactivate() {
deactivateCalled = true;
tradeStatisticsManager.getObservableTradeStatisticsSet().removeListener(setChangeListener);
tradeStatisticsManager.getObservableTradeStatisticsList().removeListener(listChangeListener);
// We want to avoid to trigger listeners in the view so we delay a bit. Deactivate on model is called before
// deactivate on view.
@ -200,7 +200,7 @@ class TradesChartsViewModel extends ActivatableViewModel {
private void applyAsyncUsdAveragePriceMapsPerTickUnit(CompletableFuture<Boolean> completeFuture) {
long ts = System.currentTimeMillis();
ChartCalculations.getUsdAveragePriceMapsPerTickUnit(tradeStatisticsManager.getObservableTradeStatisticsSet())
ChartCalculations.getUsdAveragePriceMapsPerTickUnit(tradeStatisticsManager.getObservableTradeStatisticsList())
.whenComplete((usdAveragePriceMapsPerTickUnit, throwable) -> {
if (deactivateCalled) {
return;
@ -227,7 +227,7 @@ class TradesChartsViewModel extends ActivatableViewModel {
@Nullable CompletableFuture<Boolean> completeFuture) {
CompletableFuture<Boolean> future = new CompletableFuture<>();
long ts = System.currentTimeMillis();
ChartCalculations.getTradeStatisticsForCurrency(tradeStatisticsManager.getObservableTradeStatisticsSet(),
ChartCalculations.getTradeStatisticsForCurrency(tradeStatisticsManager.getObservableTradeStatisticsList(),
currencyCode,
showAllTradeCurrenciesProperty.get())
.whenComplete((list, throwable) -> {
@ -359,7 +359,7 @@ class TradesChartsViewModel extends ActivatableViewModel {
private void fillTradeCurrencies() {
// Don't use a set as we need all entries
List<TradeCurrency> tradeCurrencyList = tradeStatisticsManager.getObservableTradeStatisticsSet().stream()
List<TradeCurrency> tradeCurrencyList = tradeStatisticsManager.getObservableTradeStatisticsList().stream()
.flatMap(e -> CurrencyUtil.getTradeCurrency(e.getCurrency()).stream())
.collect(Collectors.toList());
currencyListItems.updateWithCurrencies(tradeCurrencyList, showAllCurrencyListItem);

View file

@ -347,7 +347,7 @@ public abstract class MutableOfferDataModel extends OfferDataModel {
// Get average historic prices over for the prior trade period equaling the lock time
var blocksRange = Restrictions.getLockTime(paymentAccount.getPaymentMethod().isBlockchain());
var startDate = new Date(System.currentTimeMillis() - blocksRange * 10L * 60000);
var sortedRangeData = tradeStatisticsManager.getObservableTradeStatisticsSet().stream()
var sortedRangeData = tradeStatisticsManager.getObservableTradeStatisticsList().stream()
.filter(e -> e.getCurrency().equals(getTradeCurrency().getCode()))
.filter(e -> e.getDate().compareTo(startDate) >= 0)
.sorted(Comparator.comparing(TradeStatistics3::getDate))

View file

@ -55,7 +55,7 @@ public class CreateOfferDataModelTest {
when(preferences.isUsePercentageBasedPrice()).thenReturn(true);
when(preferences.getSecurityDepositAsPercent(null)).thenReturn(0.01);
when(createOfferService.getRandomOfferId()).thenReturn(UUID.randomUUID().toString());
when(tradeStats.getObservableTradeStatisticsSet()).thenReturn(FXCollections.observableSet());
when(tradeStats.getObservableTradeStatisticsList()).thenReturn(FXCollections.observableArrayList());
model = new CreateOfferDataModel(createOfferService,
null,

View file

@ -103,7 +103,7 @@ public class CreateOfferViewModelTest {
when(accountAgeWitnessService.getMyTradeLimit(any(), any(), any(), anyBoolean())).thenReturn(100000000L);
when(preferences.getUserCountry()).thenReturn(new Country("ES", "Spain", null));
when(createOfferService.getRandomOfferId()).thenReturn(UUID.randomUUID().toString());
when(tradeStats.getObservableTradeStatisticsSet()).thenReturn(FXCollections.observableSet());
when(tradeStats.getObservableTradeStatisticsList()).thenReturn(FXCollections.observableArrayList());
CreateOfferDataModel dataModel = new CreateOfferDataModel(createOfferService,
null,

View file

@ -99,7 +99,7 @@ public class OfferBookViewModelTest {
private PriceUtil getPriceUtil() {
PriceFeedService priceFeedService = mock(PriceFeedService.class);
TradeStatisticsManager tradeStatisticsManager = mock(TradeStatisticsManager.class);
when(tradeStatisticsManager.getObservableTradeStatisticsSet()).thenReturn(FXCollections.observableSet());
when(tradeStatisticsManager.getObservableTradeStatisticsList()).thenReturn(FXCollections.observableArrayList());
return new PriceUtil(priceFeedService, tradeStatisticsManager, empty);
}