mirror of
https://github.com/bisq-network/bisq.git
synced 2024-11-19 18:03:12 +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 class CommonOptionKeys {
|
||||||
public static final String LOG_LEVEL_KEY = "logLevel";
|
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
|
@Nullable
|
||||||
public T initAndGetPersisted(String fileName) {
|
public T initAndGetPersistedWithFileName(String fileName) {
|
||||||
this.fileName = fileName;
|
this.fileName = fileName;
|
||||||
storageFile = new File(dir, fileName);
|
storageFile = new File(dir, fileName);
|
||||||
fileManager = new FileManager<>(dir, storageFile, 300);
|
fileManager = new FileManager<>(dir, storageFile, 300);
|
||||||
|
@ -19,7 +19,7 @@ package io.bitsquare.alert;
|
|||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.name.Named;
|
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.crypto.KeyRing;
|
||||||
import io.bitsquare.p2p.P2PService;
|
import io.bitsquare.p2p.P2PService;
|
||||||
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
import io.bitsquare.p2p.storage.HashMapChangedListener;
|
||||||
@ -56,7 +56,7 @@ public class AlertManager {
|
|||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Inject
|
@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.p2PService = p2PService;
|
||||||
this.keyRing = keyRing;
|
this.keyRing = keyRing;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
@ -19,10 +19,13 @@ package io.bitsquare.alert;
|
|||||||
|
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import io.bitsquare.app.AppModule;
|
import io.bitsquare.app.AppModule;
|
||||||
|
import io.bitsquare.app.CoreOptionKeys;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
|
|
||||||
|
import static com.google.inject.name.Names.named;
|
||||||
|
|
||||||
public class AlertModule extends AppModule {
|
public class AlertModule extends AppModule {
|
||||||
private static final Logger log = LoggerFactory.getLogger(AlertModule.class);
|
private static final Logger log = LoggerFactory.getLogger(AlertModule.class);
|
||||||
|
|
||||||
@ -34,5 +37,6 @@ public class AlertModule extends AppModule {
|
|||||||
protected final void configure() {
|
protected final void configure() {
|
||||||
bind(AlertManager.class).in(Singleton.class);
|
bind(AlertManager.class).in(Singleton.class);
|
||||||
bind(PrivateNotificationManager.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.Inject;
|
||||||
import com.google.inject.name.Named;
|
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.crypto.KeyRing;
|
||||||
import io.bitsquare.crypto.DecryptedMsgWithPubKey;
|
import io.bitsquare.crypto.DecryptedMsgWithPubKey;
|
||||||
import io.bitsquare.p2p.Message;
|
import io.bitsquare.p2p.Message;
|
||||||
@ -58,7 +58,7 @@ public class PrivateNotificationManager {
|
|||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Inject
|
@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.p2PService = p2PService;
|
||||||
this.keyRing = keyRing;
|
this.keyRing = keyRing;
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ public class BitsquareEnvironment extends StandardEnvironment {
|
|||||||
private final String btcNetworkDir;
|
private final String btcNetworkDir;
|
||||||
private final String logLevel;
|
private final String logLevel;
|
||||||
private BitcoinNetwork bitcoinNetwork;
|
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) {
|
public BitsquareEnvironment(OptionSet options) {
|
||||||
this(new JOptCommandLinePropertySource(BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME, checkNotNull(
|
this(new JOptCommandLinePropertySource(BITSQUARE_COMMANDLINE_PROPERTY_SOURCE_NAME, checkNotNull(
|
||||||
@ -153,8 +153,8 @@ public class BitsquareEnvironment extends StandardEnvironment {
|
|||||||
(String) commandLineProperties.getProperty(NetworkOptionKeys.BAN_LIST) :
|
(String) commandLineProperties.getProperty(NetworkOptionKeys.BAN_LIST) :
|
||||||
"";
|
"";
|
||||||
|
|
||||||
ignoreDevMsg = commandLineProperties.containsProperty(CommonOptionKeys.IGNORE_DEV_MSG_KEY) ?
|
ignoreDevMsg = commandLineProperties.containsProperty(CoreOptionKeys.IGNORE_DEV_MSG_KEY) ?
|
||||||
(String) commandLineProperties.getProperty(CommonOptionKeys.IGNORE_DEV_MSG_KEY) :
|
(String) commandLineProperties.getProperty(CoreOptionKeys.IGNORE_DEV_MSG_KEY) :
|
||||||
"";
|
"";
|
||||||
|
|
||||||
btcSeedNodes = commandLineProperties.containsProperty(BtcOptionKeys.BTC_SEED_NODES) ?
|
btcSeedNodes = commandLineProperties.containsProperty(BtcOptionKeys.BTC_SEED_NODES) ?
|
||||||
@ -165,6 +165,10 @@ public class BitsquareEnvironment extends StandardEnvironment {
|
|||||||
(String) commandLineProperties.getProperty(BtcOptionKeys.USE_TOR_FOR_BTC) :
|
(String) commandLineProperties.getProperty(BtcOptionKeys.USE_TOR_FOR_BTC) :
|
||||||
"";
|
"";
|
||||||
|
|
||||||
|
dumpStatistics = commandLineProperties.containsProperty(CoreOptionKeys.DUMP_STATISTICS) ?
|
||||||
|
(String) commandLineProperties.getProperty(CoreOptionKeys.DUMP_STATISTICS) :
|
||||||
|
"";
|
||||||
|
|
||||||
|
|
||||||
MutablePropertySources propertySources = this.getPropertySources();
|
MutablePropertySources propertySources = this.getPropertySources();
|
||||||
propertySources.addFirst(commandLineProperties);
|
propertySources.addFirst(commandLineProperties);
|
||||||
@ -226,7 +230,8 @@ public class BitsquareEnvironment extends StandardEnvironment {
|
|||||||
setProperty(NetworkOptionKeys.SEED_NODES_KEY, seedNodes);
|
setProperty(NetworkOptionKeys.SEED_NODES_KEY, seedNodes);
|
||||||
setProperty(NetworkOptionKeys.MY_ADDRESS, myAddress);
|
setProperty(NetworkOptionKeys.MY_ADDRESS, myAddress);
|
||||||
setProperty(NetworkOptionKeys.BAN_LIST, banList);
|
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.BTC_SEED_NODES, btcSeedNodes);
|
||||||
setProperty(BtcOptionKeys.USE_TOR_FOR_BTC, useTorForBtc);
|
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.", ""))
|
parser.accepts(NetworkOptionKeys.BAN_LIST, description("Nodes to exclude from network connections.", ""))
|
||||||
.withRequiredArg();
|
.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))
|
"(Global alert, Version update alert, Filters for offers, nodes or payment account data)", false))
|
||||||
.withRequiredArg()
|
.withRequiredArg()
|
||||||
.ofType(boolean.class);
|
.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.", ""))
|
parser.accepts(BtcOptionKeys.BTC_SEED_NODES, description("Custom seed nodes used for BitcoinJ.", ""))
|
||||||
.withRequiredArg();
|
.withRequiredArg();
|
||||||
parser.accepts(BtcOptionKeys.USE_TOR_FOR_BTC, description("If set to true BitcoinJ is routed over our native Tor instance.", ""))
|
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();
|
useTor = preferences.getUseTorForBitcoinJ();
|
||||||
|
|
||||||
storage = new Storage<>(walletDir);
|
storage = new Storage<>(walletDir);
|
||||||
Long persisted = storage.initAndGetPersisted("BloomFilterNonce");
|
Long persisted = storage.initAndGetPersistedWithFileName("BloomFilterNonce");
|
||||||
if (persisted != null) {
|
if (persisted != null) {
|
||||||
bloomFilterTweak = persisted;
|
bloomFilterTweak = persisted;
|
||||||
} else {
|
} else {
|
||||||
|
@ -19,7 +19,7 @@ package io.bitsquare.filter;
|
|||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.name.Named;
|
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.crypto.KeyRing;
|
||||||
import io.bitsquare.common.util.Tuple3;
|
import io.bitsquare.common.util.Tuple3;
|
||||||
import io.bitsquare.common.util.Utilities;
|
import io.bitsquare.common.util.Utilities;
|
||||||
@ -59,7 +59,7 @@ public class FilterManager {
|
|||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Inject
|
@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.p2PService = p2PService;
|
||||||
this.keyRing = keyRing;
|
this.keyRing = keyRing;
|
||||||
this.user = user;
|
this.user = user;
|
||||||
|
@ -19,7 +19,7 @@ package io.bitsquare.filter;
|
|||||||
|
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import io.bitsquare.app.AppModule;
|
import io.bitsquare.app.AppModule;
|
||||||
import io.bitsquare.common.CommonOptionKeys;
|
import io.bitsquare.app.CoreOptionKeys;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
@ -36,6 +36,6 @@ public class FilterModule extends AppModule {
|
|||||||
@Override
|
@Override
|
||||||
protected final void configure() {
|
protected final void configure() {
|
||||||
bind(FilterManager.class).in(Singleton.class);
|
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 FailedTradesManager failedTradesManager;
|
||||||
private final ArbitratorManager arbitratorManager;
|
private final ArbitratorManager arbitratorManager;
|
||||||
private final P2PService p2PService;
|
private final P2PService p2PService;
|
||||||
private FilterManager filterManager;
|
private final FilterManager filterManager;
|
||||||
|
private final TradeStatisticsManager tradeStatisticsManager;
|
||||||
|
|
||||||
private final Storage<TradableList<Trade>> tradableListStorage;
|
private final Storage<TradableList<Trade>> tradableListStorage;
|
||||||
private final TradableList<Trade> trades;
|
private final TradableList<Trade> trades;
|
||||||
@ -107,6 +108,7 @@ public class TradeManager {
|
|||||||
P2PService p2PService,
|
P2PService p2PService,
|
||||||
PriceFeed priceFeed,
|
PriceFeed priceFeed,
|
||||||
FilterManager filterManager,
|
FilterManager filterManager,
|
||||||
|
TradeStatisticsManager tradeStatisticsManager,
|
||||||
@Named(Storage.DIR_KEY) File storageDir) {
|
@Named(Storage.DIR_KEY) File storageDir) {
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.keyRing = keyRing;
|
this.keyRing = keyRing;
|
||||||
@ -118,6 +120,7 @@ public class TradeManager {
|
|||||||
this.arbitratorManager = arbitratorManager;
|
this.arbitratorManager = arbitratorManager;
|
||||||
this.p2PService = p2PService;
|
this.p2PService = p2PService;
|
||||||
this.filterManager = filterManager;
|
this.filterManager = filterManager;
|
||||||
|
this.tradeStatisticsManager = tradeStatisticsManager;
|
||||||
|
|
||||||
tradableListStorage = new Storage<>(storageDir);
|
tradableListStorage = new Storage<>(storageDir);
|
||||||
trades = new TradableList<>(tradableListStorage, "PendingTrades");
|
trades = new TradableList<>(tradableListStorage, "PendingTrades");
|
||||||
@ -197,17 +200,7 @@ public class TradeManager {
|
|||||||
toRemove.add(trade);
|
toRemove.add(trade);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only offerer publishes statistic data of trades
|
addTradeStatistics(trade);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for (Trade trade : toAdd)
|
for (Trade trade : toAdd)
|
||||||
addTradeToFailedTrades(trade);
|
addTradeToFailedTrades(trade);
|
||||||
@ -218,25 +211,24 @@ public class TradeManager {
|
|||||||
for (Tradable tradable : closedTradableManager.getClosedTrades()) {
|
for (Tradable tradable : closedTradableManager.getClosedTrades()) {
|
||||||
if (tradable instanceof Trade) {
|
if (tradable instanceof Trade) {
|
||||||
Trade trade = (Trade) tradable;
|
Trade trade = (Trade) tradable;
|
||||||
// Only offerer publishes statistic data of trades
|
addTradeStatistics(trade);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pendingTradesInitialized.set(true);
|
pendingTradesInitialized.set(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isTradeDateValidForStatistics(Trade trade) {
|
private void addTradeStatistics(Trade trade) {
|
||||||
return (new Date().getTime() - trade.getDate().getTime()) < TimeUnit.DAYS.toMillis(20);
|
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) {
|
private void handleInitialTakeOfferRequest(TradeMessage message, NodeAddress peerNodeAddress) {
|
||||||
|
@ -19,12 +19,15 @@ package io.bitsquare.trade;
|
|||||||
|
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import io.bitsquare.app.AppModule;
|
import io.bitsquare.app.AppModule;
|
||||||
|
import io.bitsquare.app.CoreOptionKeys;
|
||||||
import io.bitsquare.trade.closed.ClosedTradableManager;
|
import io.bitsquare.trade.closed.ClosedTradableManager;
|
||||||
import io.bitsquare.trade.failed.FailedTradesManager;
|
import io.bitsquare.trade.failed.FailedTradesManager;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
|
|
||||||
|
import static com.google.inject.name.Names.named;
|
||||||
|
|
||||||
public class TradeModule extends AppModule {
|
public class TradeModule extends AppModule {
|
||||||
private static final Logger log = LoggerFactory.getLogger(TradeModule.class);
|
private static final Logger log = LoggerFactory.getLogger(TradeModule.class);
|
||||||
|
|
||||||
@ -35,7 +38,9 @@ public class TradeModule extends AppModule {
|
|||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
bind(TradeManager.class).in(Singleton.class);
|
bind(TradeManager.class).in(Singleton.class);
|
||||||
|
bind(TradeStatisticsManager.class).in(Singleton.class);
|
||||||
bind(ClosedTradableManager.class).in(Singleton.class);
|
bind(ClosedTradableManager.class).in(Singleton.class);
|
||||||
bind(FailedTradesManager.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.app.Version;
|
||||||
import io.bitsquare.common.crypto.PubKeyRing;
|
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.CapabilityRequiringPayload;
|
||||||
import io.bitsquare.p2p.storage.payload.StoragePayload;
|
import io.bitsquare.p2p.storage.payload.StoragePayload;
|
||||||
import io.bitsquare.trade.offer.Offer;
|
import io.bitsquare.trade.offer.Offer;
|
||||||
@ -16,29 +17,40 @@ import java.util.List;
|
|||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public final class TradeStatistics implements StoragePayload, CapabilityRequiringPayload {
|
public final class TradeStatistics implements StoragePayload, CapabilityRequiringPayload {
|
||||||
|
@JsonExclude
|
||||||
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
private static final long serialVersionUID = Version.P2P_NETWORK_VERSION;
|
||||||
|
@JsonExclude
|
||||||
public static final long TTL = TimeUnit.DAYS.toMillis(10);
|
public static final long TTL = TimeUnit.DAYS.toMillis(10);
|
||||||
|
|
||||||
public final Offer offer;
|
public final String currency;
|
||||||
public final long tradePriceAsLong;
|
public final Offer.Direction direction;
|
||||||
public final long tradeAmountAsLong;
|
public final long tradePrice;
|
||||||
public final long tradeDateAsTime;
|
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 String depositTxId;
|
||||||
public final byte[] contractHash;
|
@JsonExclude
|
||||||
public final PubKeyRing pubKeyRing;
|
public final PubKeyRing pubKeyRing;
|
||||||
|
|
||||||
public final int protocolVersion;
|
public TradeStatistics(Offer offer, Fiat tradePrice, Coin tradeAmount, Date tradeDate, String depositTxId, PubKeyRing pubKeyRing) {
|
||||||
|
this.direction = offer.getDirection();
|
||||||
public TradeStatistics(Offer offer, Fiat tradePrice, Coin tradeAmount, Date tradeDate, String depositTxId, byte[] contractHash, PubKeyRing pubKeyRing) {
|
this.currency = offer.getCurrencyCode();
|
||||||
this.offer = offer;
|
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.depositTxId = depositTxId;
|
||||||
this.tradePriceAsLong = tradePrice.longValue();
|
|
||||||
tradeAmountAsLong = tradeAmount.value;
|
|
||||||
this.tradeDateAsTime = tradeDate.getTime();
|
|
||||||
this.contractHash = contractHash;
|
|
||||||
this.pubKeyRing = pubKeyRing;
|
this.pubKeyRing = pubKeyRing;
|
||||||
|
|
||||||
protocolVersion = Version.TRADE_PROTOCOL_VERSION;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -59,15 +71,15 @@ public final class TradeStatistics implements StoragePayload, CapabilityRequirin
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Date getTradeDate() {
|
public Date getTradeDate() {
|
||||||
return new Date(tradeDateAsTime);
|
return new Date(tradeDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Fiat getTradePrice() {
|
public Fiat getTradePrice() {
|
||||||
return Fiat.valueOf(offer.getCurrencyCode(), tradePriceAsLong);
|
return Fiat.valueOf(currency, tradePrice);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Coin getTradeAmount() {
|
public Coin getTradeAmount() {
|
||||||
return Coin.valueOf(tradeAmountAsLong);
|
return Coin.valueOf(tradeAmount);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Fiat getTradeVolume() {
|
public Fiat getTradeVolume() {
|
||||||
@ -76,68 +88,4 @@ public final class TradeStatistics implements StoragePayload, CapabilityRequirin
|
|||||||
else
|
else
|
||||||
return null;
|
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;
|
transient private OfferAvailabilityProtocol availabilityProtocol;
|
||||||
@JsonExclude
|
@JsonExclude
|
||||||
transient private StringProperty errorMessageProperty = new SimpleStringProperty();
|
transient private StringProperty errorMessageProperty = new SimpleStringProperty();
|
||||||
|
@JsonExclude
|
||||||
transient private PriceFeed priceFeed;
|
transient private PriceFeed priceFeed;
|
||||||
|
|
||||||
|
|
||||||
|
@ -40,7 +40,6 @@ public class PublishTradeStatistics extends TradeTask {
|
|||||||
trade.getTradeAmount(),
|
trade.getTradeAmount(),
|
||||||
trade.getDate(),
|
trade.getDate(),
|
||||||
(trade.getDepositTx() != null ? trade.getDepositTx().getHashAsString() : ""),
|
(trade.getDepositTx() != null ? trade.getDepositTx().getHashAsString() : ""),
|
||||||
trade.getContractHash(),
|
|
||||||
processModel.getPubKeyRing());
|
processModel.getPubKeyRing());
|
||||||
processModel.getP2PService().addData(tradeStatistics, true);
|
processModel.getP2PService().addData(tradeStatistics, true);
|
||||||
complete();
|
complete();
|
||||||
|
@ -485,14 +485,14 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
|
|||||||
public void updateItem(final TradeStatistics item, boolean empty) {
|
public void updateItem(final TradeStatistics item, boolean empty) {
|
||||||
super.updateItem(item, empty);
|
super.updateItem(item, empty);
|
||||||
if (item != null)
|
if (item != null)
|
||||||
setText(formatter.getDirection(item.offer.getDirection()));
|
setText(formatter.getDirection(item.direction));
|
||||||
else
|
else
|
||||||
setText("");
|
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.getColumns().add(directionColumn);
|
||||||
|
|
||||||
tableView.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
|
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.gui.main.markets.trades.charts.CandleData;
|
||||||
import io.bitsquare.locale.CurrencyUtil;
|
import io.bitsquare.locale.CurrencyUtil;
|
||||||
import io.bitsquare.locale.TradeCurrency;
|
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.TradeStatistics;
|
||||||
|
import io.bitsquare.trade.TradeStatisticsManager;
|
||||||
import io.bitsquare.user.Preferences;
|
import io.bitsquare.user.Preferences;
|
||||||
import javafx.beans.property.ObjectProperty;
|
import javafx.beans.property.ObjectProperty;
|
||||||
import javafx.beans.property.SimpleObjectProperty;
|
import javafx.beans.property.SimpleObjectProperty;
|
||||||
import javafx.collections.FXCollections;
|
import javafx.collections.FXCollections;
|
||||||
import javafx.collections.ObservableList;
|
import javafx.collections.ObservableList;
|
||||||
|
import javafx.collections.SetChangeListener;
|
||||||
import javafx.scene.chart.XYChart;
|
import javafx.scene.chart.XYChart;
|
||||||
import org.bitcoinj.core.Coin;
|
import org.bitcoinj.core.Coin;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
@ -58,13 +56,12 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
|||||||
MINUTE
|
MINUTE
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private final TradeStatisticsManager tradeStatisticsManager;
|
||||||
final Preferences preferences;
|
final Preferences preferences;
|
||||||
private P2PService p2PService;
|
|
||||||
|
|
||||||
private final HashMapChangedListener mapChangedListener;
|
private final SetChangeListener<TradeStatistics> setChangeListener;
|
||||||
final ObjectProperty<TradeCurrency> tradeCurrencyProperty = new SimpleObjectProperty<>();
|
final ObjectProperty<TradeCurrency> tradeCurrencyProperty = new SimpleObjectProperty<>();
|
||||||
|
|
||||||
private final Set<TradeStatistics> allTradeStatistics = new HashSet<>();
|
|
||||||
final ObservableList<TradeStatistics> tradeStatisticsByCurrency = FXCollections.observableArrayList();
|
final ObservableList<TradeStatistics> tradeStatisticsByCurrency = FXCollections.observableArrayList();
|
||||||
ObservableList<XYChart.Data<Number, Number>> priceItems = FXCollections.observableArrayList();
|
ObservableList<XYChart.Data<Number, Number>> priceItems = FXCollections.observableArrayList();
|
||||||
ObservableList<XYChart.Data<Number, Number>> volumeItems = FXCollections.observableArrayList();
|
ObservableList<XYChart.Data<Number, Number>> volumeItems = FXCollections.observableArrayList();
|
||||||
@ -78,25 +75,11 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
|||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public TradesChartsViewModel(P2PService p2PService, Preferences preferences) {
|
public TradesChartsViewModel(TradeStatisticsManager tradeStatisticsManager, Preferences preferences) {
|
||||||
this.p2PService = p2PService;
|
this.tradeStatisticsManager = tradeStatisticsManager;
|
||||||
this.preferences = preferences;
|
this.preferences = preferences;
|
||||||
|
|
||||||
mapChangedListener = new HashMapChangedListener() {
|
setChangeListener = change -> updateChartData();
|
||||||
@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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Optional<TradeCurrency> tradeCurrencyOptional = CurrencyUtil.getTradeCurrency(preferences.getTradeStatisticsScreenCurrencyCode());
|
Optional<TradeCurrency> tradeCurrencyOptional = CurrencyUtil.getTradeCurrency(preferences.getTradeStatisticsScreenCurrencyCode());
|
||||||
if (tradeCurrencyOptional.isPresent())
|
if (tradeCurrencyOptional.isPresent())
|
||||||
@ -110,21 +93,21 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
|||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
TradesChartsViewModel() {
|
TradesChartsViewModel() {
|
||||||
mapChangedListener = null;
|
setChangeListener = null;
|
||||||
preferences = null;
|
preferences = null;
|
||||||
|
tradeStatisticsManager = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void activate() {
|
protected void activate() {
|
||||||
p2PService.getDataMap().entrySet().stream().forEach(e -> addItem(e.getValue().getStoragePayload(), false));
|
tradeStatisticsManager.getObservableTradeStatisticsSet().addListener(setChangeListener);
|
||||||
p2PService.addHashSetChangedListener(mapChangedListener);
|
|
||||||
updateChartData();
|
updateChartData();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void deactivate() {
|
protected void deactivate() {
|
||||||
p2PService.removeHashMapChangedListener(mapChangedListener);
|
tradeStatisticsManager.getObservableTradeStatisticsSet().removeListener(setChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -166,24 +149,17 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
|||||||
// Private
|
// 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() {
|
private void updateChartData() {
|
||||||
tradeStatisticsByCurrency.setAll(allTradeStatistics.stream()
|
tradeStatisticsByCurrency.setAll(tradeStatisticsManager.getObservableTradeStatisticsSet().stream()
|
||||||
.filter(e -> e.offer.getCurrencyCode().equals(getCurrencyCode()))
|
.filter(e -> e.currency.equals(getCurrencyCode()))
|
||||||
.collect(Collectors.toList()));
|
.collect(Collectors.toList()));
|
||||||
|
|
||||||
// Get all entries for the defined time interval
|
// Get all entries for the defined time interval
|
||||||
Map<Long, Set<TradeStatistics>> itemsPerInterval = new HashMap<>();
|
Map<Long, Set<TradeStatistics>> itemsPerInterval = new HashMap<>();
|
||||||
tradeStatisticsByCurrency.stream().forEach(e -> {
|
tradeStatisticsByCurrency.stream().forEach(e -> {
|
||||||
Set<TradeStatistics> set;
|
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);
|
final long now = getTickFromTime(new Date().getTime(), tickUnit);
|
||||||
long index = maxTicks - (now - time);
|
long index = maxTicks - (now - time);
|
||||||
if (itemsPerInterval.containsKey(index)) {
|
if (itemsPerInterval.containsKey(index)) {
|
||||||
@ -220,19 +196,19 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
|||||||
long accumulatedAmount = 0;
|
long accumulatedAmount = 0;
|
||||||
|
|
||||||
for (TradeStatistics item : set) {
|
for (TradeStatistics item : set) {
|
||||||
final long tradePriceAsLong = item.tradePriceAsLong;
|
final long tradePriceAsLong = item.tradePrice;
|
||||||
low = (low != 0) ? Math.min(low, tradePriceAsLong) : tradePriceAsLong;
|
low = (low != 0) ? Math.min(low, tradePriceAsLong) : tradePriceAsLong;
|
||||||
high = (high != 0) ? Math.max(high, tradePriceAsLong) : tradePriceAsLong;
|
high = (high != 0) ? Math.max(high, tradePriceAsLong) : tradePriceAsLong;
|
||||||
accumulatedVolume += item.getTradeVolume().value;
|
accumulatedVolume += (item.getTradeVolume() != null) ? item.getTradeVolume().value : 0;
|
||||||
accumulatedAmount += item.tradeAmountAsLong;
|
accumulatedAmount += item.tradeAmount;
|
||||||
}
|
}
|
||||||
long averagePrice = Math.round(accumulatedVolume * Coin.COIN.value / accumulatedAmount);
|
long averagePrice = Math.round(accumulatedVolume * Coin.COIN.value / accumulatedAmount);
|
||||||
|
|
||||||
List<TradeStatistics> list = new ArrayList<>(set);
|
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) {
|
if (list.size() > 0) {
|
||||||
open = list.get(0).tradePriceAsLong;
|
open = list.get(0).tradePrice;
|
||||||
close = list.get(list.size() - 1).tradePriceAsLong;
|
close = list.get(list.size() - 1).tradePrice;
|
||||||
}
|
}
|
||||||
boolean isBullish = close > open;
|
boolean isBullish = close > open;
|
||||||
return new CandleData(tick, open, close, high, low, averagePrice, accumulatedAmount, accumulatedVolume, isBullish);
|
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();
|
String directory = Paths.get(path).getParent().toString();
|
||||||
preferences.setDefaultPath(directory);
|
preferences.setDefaultPath(directory);
|
||||||
Storage<ArrayList<PaymentAccount>> paymentAccountsStorage = new Storage<>(new File(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) {
|
if (persisted != null) {
|
||||||
final StringBuilder msg = new StringBuilder();
|
final StringBuilder msg = new StringBuilder();
|
||||||
persisted.stream().forEach(paymentAccount -> {
|
persisted.stream().forEach(paymentAccount -> {
|
||||||
|
@ -51,10 +51,10 @@ public class TradesChartsViewModelTest {
|
|||||||
null,
|
null,
|
||||||
null,
|
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", "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, 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, 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, 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);
|
CandleData candleData = model.getCandleData(model.getTickFromTime(now.getTime(), TradesChartsViewModel.TickUnit.DAY), set);
|
||||||
assertEquals(open, candleData.open);
|
assertEquals(open, candleData.open);
|
||||||
|
@ -95,7 +95,7 @@ public class PeerManager implements ConnectionListener {
|
|||||||
this.seedNodeAddresses = new HashSet<>(seedNodeAddresses);
|
this.seedNodeAddresses = new HashSet<>(seedNodeAddresses);
|
||||||
networkNode.addConnectionListener(this);
|
networkNode.addConnectionListener(this);
|
||||||
dbStorage = new Storage<>(storageDir);
|
dbStorage = new Storage<>(storageDir);
|
||||||
HashSet<Peer> persistedPeers = dbStorage.initAndGetPersisted("PersistedPeers");
|
HashSet<Peer> persistedPeers = dbStorage.initAndGetPersistedWithFileName("PersistedPeers");
|
||||||
if (persistedPeers != null) {
|
if (persistedPeers != null) {
|
||||||
log.info("We have persisted reported peers. persistedPeers.size()=" + persistedPeers.size());
|
log.info("We have persisted reported peers. persistedPeers.size()=" + persistedPeers.size());
|
||||||
this.persistedPeers.addAll(persistedPeers);
|
this.persistedPeers.addAll(persistedPeers);
|
||||||
|
@ -72,7 +72,7 @@ public class P2PDataStorage implements MessageListener, ConnectionListener {
|
|||||||
|
|
||||||
storage = new Storage<>(storageDir);
|
storage = new Storage<>(storageDir);
|
||||||
|
|
||||||
HashMap<ByteArray, MapValue> persisted = storage.initAndGetPersisted("SequenceNumberMap");
|
HashMap<ByteArray, MapValue> persisted = storage.initAndGetPersistedWithFileName("SequenceNumberMap");
|
||||||
if (persisted != null)
|
if (persisted != null)
|
||||||
sequenceNumberMap = getPurgedSequenceNumberMap(persisted);
|
sequenceNumberMap = getPurgedSequenceNumberMap(persisted);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user