mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 09:52:23 +01:00
Add TradeStatsisticsManager, add CoreOptionKeys, rename method in Storage
This commit is contained in:
parent
242efeecb9
commit
a6660d04c9
@ -2,5 +2,5 @@ package io.bitsquare.common;
|
||||
|
||||
public class CommonOptionKeys {
|
||||
public static final String LOG_LEVEL_KEY = "logLevel";
|
||||
public static final String IGNORE_DEV_MSG_KEY = "ignoreDevMsg";
|
||||
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ public class Storage<T extends Serializable> {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public T initAndGetPersisted(String fileName) {
|
||||
public T initAndGetPersistedWithFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
storageFile = new File(dir, fileName);
|
||||
fileManager = new FileManager<>(dir, storageFile, 300);
|
||||
|
@ -19,7 +19,7 @@ package io.bitsquare.alert;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.name.Named;
|
||||
import io.bitsquare.common.CommonOptionKeys;
|
||||
import io.bitsquare.app.CoreOptionKeys;
|
||||
import io.bitsquare.common.crypto.KeyRing;
|
||||
import io.bitsquare.p2p.P2PService;
|
||||
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
||||
@ -56,7 +56,7 @@ public class AlertManager {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public AlertManager(P2PService p2PService, KeyRing keyRing, User user, @Named(CommonOptionKeys.IGNORE_DEV_MSG_KEY) boolean ignoreDevMsg) {
|
||||
public AlertManager(P2PService p2PService, KeyRing keyRing, User user, @Named(CoreOptionKeys.IGNORE_DEV_MSG_KEY) boolean ignoreDevMsg) {
|
||||
this.p2PService = p2PService;
|
||||
this.keyRing = keyRing;
|
||||
this.user = user;
|
||||
|
@ -19,10 +19,13 @@ package io.bitsquare.alert;
|
||||
|
||||
import com.google.inject.Singleton;
|
||||
import io.bitsquare.app.AppModule;
|
||||
import io.bitsquare.app.CoreOptionKeys;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import static com.google.inject.name.Names.named;
|
||||
|
||||
public class AlertModule extends AppModule {
|
||||
private static final Logger log = LoggerFactory.getLogger(AlertModule.class);
|
||||
|
||||
@ -34,5 +37,6 @@ public class AlertModule extends AppModule {
|
||||
protected final void configure() {
|
||||
bind(AlertManager.class).in(Singleton.class);
|
||||
bind(PrivateNotificationManager.class).in(Singleton.class);
|
||||
bindConstant().annotatedWith(named(CoreOptionKeys.IGNORE_DEV_MSG_KEY)).to(env.getRequiredProperty(CoreOptionKeys.IGNORE_DEV_MSG_KEY));
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ package io.bitsquare.alert;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.name.Named;
|
||||
import io.bitsquare.common.CommonOptionKeys;
|
||||
import io.bitsquare.app.CoreOptionKeys;
|
||||
import io.bitsquare.common.crypto.KeyRing;
|
||||
import io.bitsquare.crypto.DecryptedMsgWithPubKey;
|
||||
import io.bitsquare.p2p.Message;
|
||||
@ -58,7 +58,7 @@ public class PrivateNotificationManager {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public PrivateNotificationManager(P2PService p2PService, KeyRing keyRing, @Named(CommonOptionKeys.IGNORE_DEV_MSG_KEY) boolean ignoreDevMsg) {
|
||||
public PrivateNotificationManager(P2PService p2PService, KeyRing keyRing, @Named(CoreOptionKeys.IGNORE_DEV_MSG_KEY) boolean ignoreDevMsg) {
|
||||
this.p2PService = p2PService;
|
||||
this.keyRing = keyRing;
|
||||
|
||||
|
@ -85,7 +85,7 @@ public class BitsquareEnvironment extends StandardEnvironment {
|
||||
private final String btcNetworkDir;
|
||||
private final String logLevel;
|
||||
private BitcoinNetwork bitcoinNetwork;
|
||||
private final String btcSeedNodes, seedNodes, ignoreDevMsg, useTorForBtc, myAddress, banList;
|
||||
private final String btcSeedNodes, seedNodes, ignoreDevMsg, useTorForBtc, myAddress, banList, dumpStatistics;
|
||||
|
||||
public BitsquareEnvironment(OptionSet options) {
|
||||
this(new JOptCommandLinePropertySource(BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME, checkNotNull(
|
||||
@ -153,8 +153,8 @@ public class BitsquareEnvironment extends StandardEnvironment {
|
||||
(String) commandLineProperties.getProperty(NetworkOptionKeys.BAN_LIST) :
|
||||
"";
|
||||
|
||||
ignoreDevMsg = commandLineProperties.containsProperty(CommonOptionKeys.IGNORE_DEV_MSG_KEY) ?
|
||||
(String) commandLineProperties.getProperty(CommonOptionKeys.IGNORE_DEV_MSG_KEY) :
|
||||
ignoreDevMsg = commandLineProperties.containsProperty(CoreOptionKeys.IGNORE_DEV_MSG_KEY) ?
|
||||
(String) commandLineProperties.getProperty(CoreOptionKeys.IGNORE_DEV_MSG_KEY) :
|
||||
"";
|
||||
|
||||
btcSeedNodes = commandLineProperties.containsProperty(BtcOptionKeys.BTC_SEED_NODES) ?
|
||||
@ -165,6 +165,10 @@ public class BitsquareEnvironment extends StandardEnvironment {
|
||||
(String) commandLineProperties.getProperty(BtcOptionKeys.USE_TOR_FOR_BTC) :
|
||||
"";
|
||||
|
||||
dumpStatistics = commandLineProperties.containsProperty(CoreOptionKeys.DUMP_STATISTICS) ?
|
||||
(String) commandLineProperties.getProperty(CoreOptionKeys.DUMP_STATISTICS) :
|
||||
"";
|
||||
|
||||
|
||||
MutablePropertySources propertySources = this.getPropertySources();
|
||||
propertySources.addFirst(commandLineProperties);
|
||||
@ -226,7 +230,8 @@ public class BitsquareEnvironment extends StandardEnvironment {
|
||||
setProperty(NetworkOptionKeys.SEED_NODES_KEY, seedNodes);
|
||||
setProperty(NetworkOptionKeys.MY_ADDRESS, myAddress);
|
||||
setProperty(NetworkOptionKeys.BAN_LIST, banList);
|
||||
setProperty(CommonOptionKeys.IGNORE_DEV_MSG_KEY, ignoreDevMsg);
|
||||
setProperty(CoreOptionKeys.IGNORE_DEV_MSG_KEY, ignoreDevMsg);
|
||||
setProperty(CoreOptionKeys.DUMP_STATISTICS, dumpStatistics);
|
||||
|
||||
setProperty(BtcOptionKeys.BTC_SEED_NODES, btcSeedNodes);
|
||||
setProperty(BtcOptionKeys.USE_TOR_FOR_BTC, useTorForBtc);
|
||||
|
@ -86,11 +86,15 @@ public abstract class BitsquareExecutable {
|
||||
parser.accepts(NetworkOptionKeys.BAN_LIST, description("Nodes to exclude from network connections.", ""))
|
||||
.withRequiredArg();
|
||||
|
||||
parser.accepts(CommonOptionKeys.IGNORE_DEV_MSG_KEY, description("If set to true all signed messages from Bitsquare developers are ignored " +
|
||||
parser.accepts(CoreOptionKeys.IGNORE_DEV_MSG_KEY, description("If set to true all signed messages from Bitsquare developers are ignored " +
|
||||
"(Global alert, Version update alert, Filters for offers, nodes or payment account data)", false))
|
||||
.withRequiredArg()
|
||||
.ofType(boolean.class);
|
||||
|
||||
parser.accepts(CoreOptionKeys.DUMP_STATISTICS, description("If set to true the trade statistics are stored as json file in the data dir.", false))
|
||||
.withRequiredArg()
|
||||
.ofType(boolean.class);
|
||||
|
||||
parser.accepts(BtcOptionKeys.BTC_SEED_NODES, description("Custom seed nodes used for BitcoinJ.", ""))
|
||||
.withRequiredArg();
|
||||
parser.accepts(BtcOptionKeys.USE_TOR_FOR_BTC, description("If set to true BitcoinJ is routed over our native Tor instance.", ""))
|
||||
|
7
core/src/main/java/io/bitsquare/app/CoreOptionKeys.java
Normal file
7
core/src/main/java/io/bitsquare/app/CoreOptionKeys.java
Normal file
@ -0,0 +1,7 @@
|
||||
package io.bitsquare.app;
|
||||
|
||||
public class CoreOptionKeys {
|
||||
public static final String IGNORE_DEV_MSG_KEY = "ignoreDevMsg";
|
||||
public static final String DUMP_STATISTICS = "dumpStatistics";
|
||||
|
||||
}
|
@ -135,7 +135,7 @@ public class WalletService {
|
||||
useTor = preferences.getUseTorForBitcoinJ();
|
||||
|
||||
storage = new Storage<>(walletDir);
|
||||
Long persisted = storage.initAndGetPersisted("BloomFilterNonce");
|
||||
Long persisted = storage.initAndGetPersistedWithFileName("BloomFilterNonce");
|
||||
if (persisted != null) {
|
||||
bloomFilterTweak = persisted;
|
||||
} else {
|
||||
|
@ -19,7 +19,7 @@ package io.bitsquare.filter;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.name.Named;
|
||||
import io.bitsquare.common.CommonOptionKeys;
|
||||
import io.bitsquare.app.CoreOptionKeys;
|
||||
import io.bitsquare.common.crypto.KeyRing;
|
||||
import io.bitsquare.common.util.Tuple3;
|
||||
import io.bitsquare.common.util.Utilities;
|
||||
@ -59,7 +59,7 @@ public class FilterManager {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public FilterManager(P2PService p2PService, KeyRing keyRing, User user, @Named(CommonOptionKeys.IGNORE_DEV_MSG_KEY) boolean ignoreDevMsg) {
|
||||
public FilterManager(P2PService p2PService, KeyRing keyRing, User user, @Named(CoreOptionKeys.IGNORE_DEV_MSG_KEY) boolean ignoreDevMsg) {
|
||||
this.p2PService = p2PService;
|
||||
this.keyRing = keyRing;
|
||||
this.user = user;
|
||||
|
@ -19,7 +19,7 @@ package io.bitsquare.filter;
|
||||
|
||||
import com.google.inject.Singleton;
|
||||
import io.bitsquare.app.AppModule;
|
||||
import io.bitsquare.common.CommonOptionKeys;
|
||||
import io.bitsquare.app.CoreOptionKeys;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.env.Environment;
|
||||
@ -36,6 +36,6 @@ public class FilterModule extends AppModule {
|
||||
@Override
|
||||
protected final void configure() {
|
||||
bind(FilterManager.class).in(Singleton.class);
|
||||
bindConstant().annotatedWith(named(CommonOptionKeys.IGNORE_DEV_MSG_KEY)).to(env.getRequiredProperty(CommonOptionKeys.IGNORE_DEV_MSG_KEY));
|
||||
bindConstant().annotatedWith(named(CoreOptionKeys.IGNORE_DEV_MSG_KEY)).to(env.getRequiredProperty(CoreOptionKeys.IGNORE_DEV_MSG_KEY));
|
||||
}
|
||||
}
|
||||
|
@ -84,7 +84,8 @@ public class TradeManager {
|
||||
private final FailedTradesManager failedTradesManager;
|
||||
private final ArbitratorManager arbitratorManager;
|
||||
private final P2PService p2PService;
|
||||
private FilterManager filterManager;
|
||||
private final FilterManager filterManager;
|
||||
private final TradeStatisticsManager tradeStatisticsManager;
|
||||
|
||||
private final Storage<TradableList<Trade>> tradableListStorage;
|
||||
private final TradableList<Trade> trades;
|
||||
@ -107,6 +108,7 @@ public class TradeManager {
|
||||
P2PService p2PService,
|
||||
PriceFeed priceFeed,
|
||||
FilterManager filterManager,
|
||||
TradeStatisticsManager tradeStatisticsManager,
|
||||
@Named(Storage.DIR_KEY) File storageDir) {
|
||||
this.user = user;
|
||||
this.keyRing = keyRing;
|
||||
@ -118,6 +120,7 @@ public class TradeManager {
|
||||
this.arbitratorManager = arbitratorManager;
|
||||
this.p2PService = p2PService;
|
||||
this.filterManager = filterManager;
|
||||
this.tradeStatisticsManager = tradeStatisticsManager;
|
||||
|
||||
tradableListStorage = new Storage<>(storageDir);
|
||||
trades = new TradableList<>(tradableListStorage, "PendingTrades");
|
||||
@ -197,17 +200,7 @@ public class TradeManager {
|
||||
toRemove.add(trade);
|
||||
}
|
||||
|
||||
// Only offerer publishes statistic data of trades
|
||||
if (isMyOffer(trade.getOffer()) && isTradeDateValidForStatistics(trade)) {
|
||||
TradeStatistics tradeStatistics = new TradeStatistics(trade.getOffer(),
|
||||
trade.getTradePrice(),
|
||||
trade.getTradeAmount(),
|
||||
trade.getDate(),
|
||||
(trade.getDepositTx() != null ? trade.getDepositTx().getHashAsString() : ""),
|
||||
trade.getContractHash(),
|
||||
keyRing.getPubKeyRing());
|
||||
p2PService.addData(tradeStatistics, true);
|
||||
}
|
||||
addTradeStatistics(trade);
|
||||
}
|
||||
for (Trade trade : toAdd)
|
||||
addTradeToFailedTrades(trade);
|
||||
@ -218,25 +211,24 @@ public class TradeManager {
|
||||
for (Tradable tradable : closedTradableManager.getClosedTrades()) {
|
||||
if (tradable instanceof Trade) {
|
||||
Trade trade = (Trade) tradable;
|
||||
// Only offerer publishes statistic data of trades
|
||||
if (isMyOffer(trade.getOffer()) && isTradeDateValidForStatistics(trade)) {
|
||||
TradeStatistics tradeStatistics = new TradeStatistics(trade.getOffer(),
|
||||
trade.getTradePrice(),
|
||||
trade.getTradeAmount(),
|
||||
trade.getDate(),
|
||||
(trade.getDepositTx() != null ? trade.getDepositTx().getHashAsString() : ""),
|
||||
trade.getContractHash(),
|
||||
keyRing.getPubKeyRing());
|
||||
p2PService.addData(tradeStatistics, true);
|
||||
}
|
||||
addTradeStatistics(trade);
|
||||
}
|
||||
}
|
||||
|
||||
pendingTradesInitialized.set(true);
|
||||
}
|
||||
|
||||
private boolean isTradeDateValidForStatistics(Trade trade) {
|
||||
return (new Date().getTime() - trade.getDate().getTime()) < TimeUnit.DAYS.toMillis(20);
|
||||
private void addTradeStatistics(Trade trade) {
|
||||
TradeStatistics tradeStatistics = new TradeStatistics(trade.getOffer(),
|
||||
trade.getTradePrice(),
|
||||
trade.getTradeAmount(),
|
||||
trade.getDate(),
|
||||
(trade.getDepositTx() != null ? trade.getDepositTx().getHashAsString() : ""),
|
||||
keyRing.getPubKeyRing());
|
||||
tradeStatisticsManager.add(tradeStatistics);
|
||||
// Only offerer publishes statistic data of trades, only trades from last 20 days
|
||||
if (isMyOffer(trade.getOffer()) && (new Date().getTime() - trade.getDate().getTime()) < TimeUnit.DAYS.toMillis(20))
|
||||
p2PService.addData(tradeStatistics, true);
|
||||
}
|
||||
|
||||
private void handleInitialTakeOfferRequest(TradeMessage message, NodeAddress peerNodeAddress) {
|
||||
|
@ -19,12 +19,15 @@ package io.bitsquare.trade;
|
||||
|
||||
import com.google.inject.Singleton;
|
||||
import io.bitsquare.app.AppModule;
|
||||
import io.bitsquare.app.CoreOptionKeys;
|
||||
import io.bitsquare.trade.closed.ClosedTradableManager;
|
||||
import io.bitsquare.trade.failed.FailedTradesManager;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
import static com.google.inject.name.Names.named;
|
||||
|
||||
public class TradeModule extends AppModule {
|
||||
private static final Logger log = LoggerFactory.getLogger(TradeModule.class);
|
||||
|
||||
@ -35,7 +38,9 @@ public class TradeModule extends AppModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
bind(TradeManager.class).in(Singleton.class);
|
||||
bind(TradeStatisticsManager.class).in(Singleton.class);
|
||||
bind(ClosedTradableManager.class).in(Singleton.class);
|
||||
bind(FailedTradesManager.class).in(Singleton.class);
|
||||
bindConstant().annotatedWith(named(CoreOptionKeys.DUMP_STATISTICS)).to(env.getRequiredProperty(CoreOptionKeys.DUMP_STATISTICS));
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,7 @@ package io.bitsquare.trade;
|
||||
|
||||
import io.bitsquare.app.Version;
|
||||
import io.bitsquare.common.crypto.PubKeyRing;
|
||||
import io.bitsquare.common.util.JsonExclude;
|
||||
import io.bitsquare.p2p.storage.payload.CapabilityRequiringPayload;
|
||||
import io.bitsquare.p2p.storage.payload.StoragePayload;
|
||||
import io.bitsquare.trade.offer.Offer;
|
||||
@ -16,29 +17,40 @@ import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class TradeStatistics implements StoragePayload, CapabilityRequiringPayload {
|
||||
@JsonExclude
|
||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||
@JsonExclude
|
||||
public static final long TTL = TimeUnit.DAYS.toMillis(10);
|
||||
|
||||
public final Offer offer;
|
||||
public final long tradePriceAsLong;
|
||||
public final long tradeAmountAsLong;
|
||||
public final long tradeDateAsTime;
|
||||
public final String currency;
|
||||
public final Offer.Direction direction;
|
||||
public final long tradePrice;
|
||||
public final long tradeAmount;
|
||||
public final long tradeDate;
|
||||
public final String paymentMethod;
|
||||
public final long offerDate;
|
||||
public final boolean useMarketBasedPrice;
|
||||
public final double marketPriceMargin;
|
||||
public final long offerAmount;
|
||||
public final long offerMinAmount;
|
||||
public final String depositTxId;
|
||||
public final byte[] contractHash;
|
||||
@JsonExclude
|
||||
public final PubKeyRing pubKeyRing;
|
||||
|
||||
public final int protocolVersion;
|
||||
|
||||
public TradeStatistics(Offer offer, Fiat tradePrice, Coin tradeAmount, Date tradeDate, String depositTxId, byte[] contractHash, PubKeyRing pubKeyRing) {
|
||||
this.offer = offer;
|
||||
public TradeStatistics(Offer offer, Fiat tradePrice, Coin tradeAmount, Date tradeDate, String depositTxId, PubKeyRing pubKeyRing) {
|
||||
this.direction = offer.getDirection();
|
||||
this.currency = offer.getCurrencyCode();
|
||||
this.paymentMethod = offer.getPaymentMethod().getId();
|
||||
this.offerDate = offer.getDate().getTime();
|
||||
this.useMarketBasedPrice = offer.getUseMarketBasedPrice();
|
||||
this.marketPriceMargin = offer.getMarketPriceMargin();
|
||||
this.offerAmount = offer.getAmount().value;
|
||||
this.offerMinAmount = offer.getMinAmount().value;
|
||||
this.tradePrice = tradePrice.longValue();
|
||||
this.tradeAmount = tradeAmount.value;
|
||||
this.tradeDate = tradeDate.getTime();
|
||||
this.depositTxId = depositTxId;
|
||||
this.tradePriceAsLong = tradePrice.longValue();
|
||||
tradeAmountAsLong = tradeAmount.value;
|
||||
this.tradeDateAsTime = tradeDate.getTime();
|
||||
this.contractHash = contractHash;
|
||||
this.pubKeyRing = pubKeyRing;
|
||||
|
||||
protocolVersion = Version.TRADE_PROTOCOL_VERSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -59,15 +71,15 @@ public final class TradeStatistics implements StoragePayload, CapabilityRequirin
|
||||
}
|
||||
|
||||
public Date getTradeDate() {
|
||||
return new Date(tradeDateAsTime);
|
||||
return new Date(tradeDate);
|
||||
}
|
||||
|
||||
public Fiat getTradePrice() {
|
||||
return Fiat.valueOf(offer.getCurrencyCode(), tradePriceAsLong);
|
||||
return Fiat.valueOf(currency, tradePrice);
|
||||
}
|
||||
|
||||
public Coin getTradeAmount() {
|
||||
return Coin.valueOf(tradeAmountAsLong);
|
||||
return Coin.valueOf(tradeAmount);
|
||||
}
|
||||
|
||||
public Fiat getTradeVolume() {
|
||||
@ -76,68 +88,4 @@ public final class TradeStatistics implements StoragePayload, CapabilityRequirin
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
// We compare the objects of both traders to match.
|
||||
// pubKeyRing is not matching so we excluded it
|
||||
public boolean isSameTrade(TradeStatistics o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof TradeStatistics)) return false;
|
||||
|
||||
TradeStatistics that = (TradeStatistics) o;
|
||||
|
||||
if (tradePriceAsLong != that.tradePriceAsLong) return false;
|
||||
if (tradeAmountAsLong != that.tradeAmountAsLong) return false;
|
||||
if (tradeDateAsTime != that.tradeDateAsTime) return false;
|
||||
if (protocolVersion != that.protocolVersion) return false;
|
||||
if (offer != null ? !offer.equals(that.offer) : that.offer != null) return false;
|
||||
if (depositTxId != null ? !depositTxId.equals(that.depositTxId) : that.depositTxId != null) return false;
|
||||
return Arrays.equals(contractHash, that.contractHash);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof TradeStatistics)) return false;
|
||||
|
||||
TradeStatistics that = (TradeStatistics) o;
|
||||
|
||||
if (tradePriceAsLong != that.tradePriceAsLong) return false;
|
||||
if (tradeAmountAsLong != that.tradeAmountAsLong) return false;
|
||||
if (tradeDateAsTime != that.tradeDateAsTime) return false;
|
||||
if (protocolVersion != that.protocolVersion) return false;
|
||||
if (offer != null ? !offer.equals(that.offer) : that.offer != null) return false;
|
||||
if (depositTxId != null ? !depositTxId.equals(that.depositTxId) : that.depositTxId != null) return false;
|
||||
if (!Arrays.equals(contractHash, that.contractHash)) return false;
|
||||
return !(pubKeyRing != null ? !pubKeyRing.equals(that.pubKeyRing) : that.pubKeyRing != null);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = offer != null ? offer.hashCode() : 0;
|
||||
result = 31 * result + (int) (tradePriceAsLong ^ (tradePriceAsLong >>> 32));
|
||||
result = 31 * result + (int) (tradeAmountAsLong ^ (tradeAmountAsLong >>> 32));
|
||||
result = 31 * result + (int) (tradeDateAsTime ^ (tradeDateAsTime >>> 32));
|
||||
result = 31 * result + (depositTxId != null ? depositTxId.hashCode() : 0);
|
||||
result = 31 * result + (contractHash != null ? Arrays.hashCode(contractHash) : 0);
|
||||
result = 31 * result + (pubKeyRing != null ? pubKeyRing.hashCode() : 0);
|
||||
result = 31 * result + protocolVersion;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TradeStatistics{" +
|
||||
"offer=" + offer +
|
||||
", tradePriceAsLong=" + tradePriceAsLong +
|
||||
", tradeAmountAsLong=" + tradeAmountAsLong +
|
||||
", tradeDateAsTime=" + tradeDateAsTime +
|
||||
", depositTxId='" + depositTxId + '\'' +
|
||||
", contractHash=" + Arrays.toString(contractHash) +
|
||||
", pubKeyRing=" + pubKeyRing +
|
||||
", protocolVersion=" + protocolVersion +
|
||||
'}';
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,84 @@
|
||||
package io.bitsquare.trade;
|
||||
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.name.Named;
|
||||
import io.bitsquare.app.CoreOptionKeys;
|
||||
import io.bitsquare.common.util.Utilities;
|
||||
import io.bitsquare.p2p.P2PService;
|
||||
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
||||
import io.bitsquare.p2p.storage.payload.StoragePayload;
|
||||
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
|
||||
import io.bitsquare.storage.Storage;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableSet;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class TradeStatisticsManager {
|
||||
private static final Logger log = LoggerFactory.getLogger(TradeStatisticsManager.class);
|
||||
private final Storage<HashSet<TradeStatistics>> storage;
|
||||
private Storage<String> jsonStorage;
|
||||
private boolean dumpStatistics;
|
||||
|
||||
private ObservableSet<TradeStatistics> observableTradeStatisticsSet = FXCollections.observableSet();
|
||||
private HashSet<TradeStatistics> tradeStatisticsSet = new HashSet<>();
|
||||
|
||||
@Inject
|
||||
public TradeStatisticsManager(Storage<HashSet<TradeStatistics>> storage, Storage<String> jsonStorage, P2PService p2PService, @Named(CoreOptionKeys.DUMP_STATISTICS) boolean dumpStatistics) {
|
||||
this.storage = storage;
|
||||
this.jsonStorage = jsonStorage;
|
||||
this.dumpStatistics = dumpStatistics;
|
||||
|
||||
if (dumpStatistics)
|
||||
this.jsonStorage.initAndGetPersistedWithFileName("trade_statistics.json");
|
||||
|
||||
HashSet<TradeStatistics> persisted = storage.initAndGetPersistedWithFileName("TradeStatistics");
|
||||
if (persisted != null)
|
||||
observableTradeStatisticsSet = FXCollections.observableSet(persisted);
|
||||
|
||||
p2PService.addHashSetChangedListener(new HashMapChangedListener() {
|
||||
@Override
|
||||
public void onAdded(ProtectedStorageEntry data) {
|
||||
final StoragePayload storagePayload = data.getStoragePayload();
|
||||
if (storagePayload instanceof TradeStatistics) {
|
||||
add((TradeStatistics) storagePayload);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoved(ProtectedStorageEntry data) {
|
||||
// We don't remove items
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void add(TradeStatistics tradeStatistics) {
|
||||
if (!observableTradeStatisticsSet.contains(tradeStatistics)) {
|
||||
observableTradeStatisticsSet.add(tradeStatistics);
|
||||
tradeStatisticsSet.add(tradeStatistics);
|
||||
storage.queueUpForSave(tradeStatisticsSet, 2000);
|
||||
|
||||
if (dumpStatistics) {
|
||||
// We store the statistics as json so it is easy for further processing (e.g. for web based services)
|
||||
// TODO This is just a quick solution for storing to one file.
|
||||
// 1 statistic entry has 500 bytes as json.
|
||||
// Need a more scalable solution later when we get more volume.
|
||||
// The flag will only be activated by dedicated nodes, so it should not be too critical for the moment, but needs to
|
||||
// get improved. Maybe a LevelDB like DB...? Could be impl. in a headless version only.
|
||||
List<TradeStatistics> list = tradeStatisticsSet.stream().collect(Collectors.toList());
|
||||
list.sort((o1, o2) -> (o1.tradeDate < o2.tradeDate ? 1 : (o1.tradeDate == o2.tradeDate ? 0 : -1)));
|
||||
TradeStatistics[] array = new TradeStatistics[tradeStatisticsSet.size()];
|
||||
list.toArray(array);
|
||||
jsonStorage.queueUpForSave(Utilities.objectToJson(array), 5_000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableSet<TradeStatistics> getObservableTradeStatisticsSet() {
|
||||
return observableTradeStatisticsSet;
|
||||
}
|
||||
}
|
@ -144,6 +144,7 @@ public final class Offer implements StoragePayload, RequiresOwnerIsOnlinePayload
|
||||
transient private OfferAvailabilityProtocol availabilityProtocol;
|
||||
@JsonExclude
|
||||
transient private StringProperty errorMessageProperty = new SimpleStringProperty();
|
||||
@JsonExclude
|
||||
transient private PriceFeed priceFeed;
|
||||
|
||||
|
||||
|
@ -40,7 +40,6 @@ public class PublishTradeStatistics extends TradeTask {
|
||||
trade.getTradeAmount(),
|
||||
trade.getDate(),
|
||||
(trade.getDepositTx() != null ? trade.getDepositTx().getHashAsString() : ""),
|
||||
trade.getContractHash(),
|
||||
processModel.getPubKeyRing());
|
||||
processModel.getP2PService().addData(tradeStatistics, true);
|
||||
complete();
|
||||
|
@ -485,14 +485,14 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
|
||||
public void updateItem(final TradeStatistics item, boolean empty) {
|
||||
super.updateItem(item, empty);
|
||||
if (item != null)
|
||||
setText(formatter.getDirection(item.offer.getDirection()));
|
||||
setText(formatter.getDirection(item.direction));
|
||||
else
|
||||
setText("");
|
||||
}
|
||||
};
|
||||
}
|
||||
});
|
||||
directionColumn.setComparator((o1, o2) -> o1.offer.getDirection().compareTo(o2.offer.getDirection()));
|
||||
directionColumn.setComparator((o1, o2) -> o1.direction.compareTo(o2.direction));
|
||||
tableView.getColumns().add(directionColumn);
|
||||
|
||||
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
||||
|
@ -23,16 +23,14 @@ import io.bitsquare.gui.common.model.ActivatableViewModel;
|
||||
import io.bitsquare.gui.main.markets.trades.charts.CandleData;
|
||||
import io.bitsquare.locale.CurrencyUtil;
|
||||
import io.bitsquare.locale.TradeCurrency;
|
||||
import io.bitsquare.p2p.P2PService;
|
||||
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
||||
import io.bitsquare.p2p.storage.payload.StoragePayload;
|
||||
import io.bitsquare.p2p.storage.storageentry.ProtectedStorageEntry;
|
||||
import io.bitsquare.trade.TradeStatistics;
|
||||
import io.bitsquare.trade.TradeStatisticsManager;
|
||||
import io.bitsquare.user.Preferences;
|
||||
import javafx.beans.property.ObjectProperty;
|
||||
import javafx.beans.property.SimpleObjectProperty;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ObservableList;
|
||||
import javafx.collections.SetChangeListener;
|
||||
import javafx.scene.chart.XYChart;
|
||||
import org.bitcoinj.core.Coin;
|
||||
import org.slf4j.Logger;
|
||||
@ -58,13 +56,12 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
||||
MINUTE
|
||||
}
|
||||
|
||||
private final TradeStatisticsManager tradeStatisticsManager;
|
||||
final Preferences preferences;
|
||||
private P2PService p2PService;
|
||||
|
||||
private final HashMapChangedListener mapChangedListener;
|
||||
private final SetChangeListener<TradeStatistics> setChangeListener;
|
||||
final ObjectProperty<TradeCurrency> tradeCurrencyProperty = new SimpleObjectProperty<>();
|
||||
|
||||
private final Set<TradeStatistics> allTradeStatistics = new HashSet<>();
|
||||
final ObservableList<TradeStatistics> tradeStatisticsByCurrency = FXCollections.observableArrayList();
|
||||
ObservableList<XYChart.Data<Number, Number>> priceItems = FXCollections.observableArrayList();
|
||||
ObservableList<XYChart.Data<Number, Number>> volumeItems = FXCollections.observableArrayList();
|
||||
@ -78,25 +75,11 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Inject
|
||||
public TradesChartsViewModel(P2PService p2PService, Preferences preferences) {
|
||||
this.p2PService = p2PService;
|
||||
public TradesChartsViewModel(TradeStatisticsManager tradeStatisticsManager, Preferences preferences) {
|
||||
this.tradeStatisticsManager = tradeStatisticsManager;
|
||||
this.preferences = preferences;
|
||||
|
||||
mapChangedListener = new HashMapChangedListener() {
|
||||
@Override
|
||||
public void onAdded(ProtectedStorageEntry data) {
|
||||
addItem(data.getStoragePayload(), true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRemoved(ProtectedStorageEntry data) {
|
||||
final StoragePayload storagePayload = data.getStoragePayload();
|
||||
if (storagePayload instanceof TradeStatistics && allTradeStatistics.contains(storagePayload)) {
|
||||
allTradeStatistics.remove(storagePayload);
|
||||
updateChartData();
|
||||
}
|
||||
}
|
||||
};
|
||||
setChangeListener = change -> updateChartData();
|
||||
|
||||
Optional<TradeCurrency> tradeCurrencyOptional = CurrencyUtil.getTradeCurrency(preferences.getTradeStatisticsScreenCurrencyCode());
|
||||
if (tradeCurrencyOptional.isPresent())
|
||||
@ -110,21 +93,21 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
||||
|
||||
@VisibleForTesting
|
||||
TradesChartsViewModel() {
|
||||
mapChangedListener = null;
|
||||
setChangeListener = null;
|
||||
preferences = null;
|
||||
tradeStatisticsManager = null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
p2PService.getDataMap().entrySet().stream().forEach(e -> addItem(e.getValue().getStoragePayload(), false));
|
||||
p2PService.addHashSetChangedListener(mapChangedListener);
|
||||
tradeStatisticsManager.getObservableTradeStatisticsSet().addListener(setChangeListener);
|
||||
updateChartData();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
p2PService.removeHashMapChangedListener(mapChangedListener);
|
||||
tradeStatisticsManager.getObservableTradeStatisticsSet().removeListener(setChangeListener);
|
||||
}
|
||||
|
||||
|
||||
@ -166,24 +149,17 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
||||
// Private
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void addItem(StoragePayload storagePayload, boolean doUpdate) {
|
||||
if (storagePayload instanceof TradeStatistics && !allTradeStatistics.contains(storagePayload)) {
|
||||
allTradeStatistics.add((TradeStatistics) storagePayload);
|
||||
if (doUpdate)
|
||||
updateChartData();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateChartData() {
|
||||
tradeStatisticsByCurrency.setAll(allTradeStatistics.stream()
|
||||
.filter(e -> e.offer.getCurrencyCode().equals(getCurrencyCode()))
|
||||
tradeStatisticsByCurrency.setAll(tradeStatisticsManager.getObservableTradeStatisticsSet().stream()
|
||||
.filter(e -> e.currency.equals(getCurrencyCode()))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
// Get all entries for the defined time interval
|
||||
Map<Long, Set<TradeStatistics>> itemsPerInterval = new HashMap<>();
|
||||
tradeStatisticsByCurrency.stream().forEach(e -> {
|
||||
Set<TradeStatistics> set;
|
||||
final long time = getTickFromTime(e.tradeDateAsTime, tickUnit);
|
||||
final long time = getTickFromTime(e.tradeDate, tickUnit);
|
||||
final long now = getTickFromTime(new Date().getTime(), tickUnit);
|
||||
long index = maxTicks - (now - time);
|
||||
if (itemsPerInterval.containsKey(index)) {
|
||||
@ -220,19 +196,19 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
||||
long accumulatedAmount = 0;
|
||||
|
||||
for (TradeStatistics item : set) {
|
||||
final long tradePriceAsLong = item.tradePriceAsLong;
|
||||
final long tradePriceAsLong = item.tradePrice;
|
||||
low = (low != 0) ? Math.min(low, tradePriceAsLong) : tradePriceAsLong;
|
||||
high = (high != 0) ? Math.max(high, tradePriceAsLong) : tradePriceAsLong;
|
||||
accumulatedVolume += item.getTradeVolume().value;
|
||||
accumulatedAmount += item.tradeAmountAsLong;
|
||||
accumulatedVolume += (item.getTradeVolume() != null) ? item.getTradeVolume().value : 0;
|
||||
accumulatedAmount += item.tradeAmount;
|
||||
}
|
||||
long averagePrice = Math.round(accumulatedVolume * Coin.COIN.value / accumulatedAmount);
|
||||
|
||||
List<TradeStatistics> list = new ArrayList<>(set);
|
||||
list.sort((o1, o2) -> (o1.tradeDateAsTime < o2.tradeDateAsTime ? -1 : (o1.tradeDateAsTime == o2.tradeDateAsTime ? 0 : 1)));
|
||||
list.sort((o1, o2) -> (o1.tradeDate < o2.tradeDate ? -1 : (o1.tradeDate == o2.tradeDate ? 0 : 1)));
|
||||
if (list.size() > 0) {
|
||||
open = list.get(0).tradePriceAsLong;
|
||||
close = list.get(list.size() - 1).tradePriceAsLong;
|
||||
open = list.get(0).tradePrice;
|
||||
close = list.get(list.size() - 1).tradePrice;
|
||||
}
|
||||
boolean isBullish = close > open;
|
||||
return new CandleData(tick, open, close, high, low, averagePrice, accumulatedAmount, accumulatedVolume, isBullish);
|
||||
|
@ -99,7 +99,7 @@ public class GUIUtil {
|
||||
String directory = Paths.get(path).getParent().toString();
|
||||
preferences.setDefaultPath(directory);
|
||||
Storage<ArrayList<PaymentAccount>> paymentAccountsStorage = new Storage<>(new File(directory));
|
||||
ArrayList<PaymentAccount> persisted = paymentAccountsStorage.initAndGetPersisted(fileName);
|
||||
ArrayList<PaymentAccount> persisted = paymentAccountsStorage.initAndGetPersistedWithFileName(fileName);
|
||||
if (persisted != null) {
|
||||
final StringBuilder msg = new StringBuilder();
|
||||
persisted.stream().forEach(paymentAccount -> {
|
||||
|
@ -51,10 +51,10 @@ public class TradesChartsViewModelTest {
|
||||
null,
|
||||
null,
|
||||
null);
|
||||
set.add(new TradeStatistics(offer, Fiat.parseFiat("EUR", "520"), Coin.parseCoin("1"), new Date(now.getTime()), null, null, null));
|
||||
set.add(new TradeStatistics(offer, Fiat.parseFiat("EUR", "500"), Coin.parseCoin("1"), new Date(now.getTime() + 100), null, null, null));
|
||||
set.add(new TradeStatistics(offer, Fiat.parseFiat("EUR", "600"), Coin.parseCoin("1"), new Date(now.getTime() + 200), null, null, null));
|
||||
set.add(new TradeStatistics(offer, Fiat.parseFiat("EUR", "580"), Coin.parseCoin("1"), new Date(now.getTime() + 300), null, null, null));
|
||||
set.add(new TradeStatistics(offer, Fiat.parseFiat("EUR", "520"), Coin.parseCoin("1"), new Date(now.getTime()), null, null));
|
||||
set.add(new TradeStatistics(offer, Fiat.parseFiat("EUR", "500"), Coin.parseCoin("1"), new Date(now.getTime() + 100), null, null));
|
||||
set.add(new TradeStatistics(offer, Fiat.parseFiat("EUR", "600"), Coin.parseCoin("1"), new Date(now.getTime() + 200), null, null));
|
||||
set.add(new TradeStatistics(offer, Fiat.parseFiat("EUR", "580"), Coin.parseCoin("1"), new Date(now.getTime() + 300), null, null));
|
||||
|
||||
CandleData candleData = model.getCandleData(model.getTickFromTime(now.getTime(), TradesChartsViewModel.TickUnit.DAY), set);
|
||||
assertEquals(open, candleData.open);
|
||||
|
@ -95,7 +95,7 @@ public class PeerManager implements ConnectionListener {
|
||||
this.seedNodeAddresses = new HashSet<>(seedNodeAddresses);
|
||||
networkNode.addConnectionListener(this);
|
||||
dbStorage = new Storage<>(storageDir);
|
||||
HashSet<Peer> persistedPeers = dbStorage.initAndGetPersisted("PersistedPeers");
|
||||
HashSet<Peer> persistedPeers = dbStorage.initAndGetPersistedWithFileName("PersistedPeers");
|
||||
if (persistedPeers != null) {
|
||||
log.info("We have persisted reported peers. persistedPeers.size()=" + persistedPeers.size());
|
||||
this.persistedPeers.addAll(persistedPeers);
|
||||
|
@ -72,7 +72,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
||||
|
||||
storage = new Storage<>(storageDir);
|
||||
|
||||
HashMap<ByteArray, MapValue> persisted = storage.initAndGetPersisted("SequenceNumberMap");
|
||||
HashMap<ByteArray, MapValue> persisted = storage.initAndGetPersistedWithFileName("SequenceNumberMap");
|
||||
if (persisted != null)
|
||||
sequenceNumberMap = getPurgedSequenceNumberMap(persisted);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user