mirror of
https://github.com/bisq-network/bisq.git
synced 2025-02-24 15:10:44 +01:00
Update chart
This commit is contained in:
parent
bd4f0742fd
commit
5ca8ae8f34
6 changed files with 327 additions and 155 deletions
|
@ -38,7 +38,7 @@
|
|||
}
|
||||
|
||||
.candlestick-average-line {
|
||||
-fx-stroke: #106ece;
|
||||
-fx-stroke: #00b2ff;
|
||||
-fx-stroke-width: 2px;
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@
|
|||
|
||||
.candlestick-bar {
|
||||
-fx-padding: 5;
|
||||
-demo-bar-fill: red;
|
||||
-demo-bar-fill: #e81a00;
|
||||
-fx-background-color: linear-gradient(derive(-demo-bar-fill, -30%), derive(-demo-bar-fill, -40%)),
|
||||
linear-gradient(derive(-demo-bar-fill, 100%), derive(-demo-bar-fill, 10%)),
|
||||
linear-gradient(derive(-demo-bar-fill, 30%), derive(-demo-bar-fill, -10%));
|
||||
|
@ -61,9 +61,35 @@
|
|||
}
|
||||
|
||||
.candlestick-bar.close-above-open {
|
||||
-demo-bar-fill: #95ce1b;
|
||||
-demo-bar-fill: #1bff06;
|
||||
}
|
||||
|
||||
.candlestick-bar.open-above-close {
|
||||
-demo-bar-fill: #ce2700;
|
||||
-demo-bar-fill: #e81a00;
|
||||
}
|
||||
|
||||
.candlestick-bar.empty {
|
||||
-demo-bar-fill: #cccccc;
|
||||
}
|
||||
|
||||
.chart-plot-background {
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
.default-color0.chart-series-line {
|
||||
-fx-stroke: blue;
|
||||
}
|
||||
|
||||
.default-color0.chart-line-symbol {
|
||||
-fx-background-color: blue, white;
|
||||
}
|
||||
|
||||
.chart-plot-background {
|
||||
-fx-background-color: transparent;
|
||||
}
|
||||
|
||||
.chart-alternative-row-fill {
|
||||
-fx-fill: transparent;
|
||||
-fx-stroke: transparent;
|
||||
-fx-stroke-width: 0;
|
||||
}
|
|
@ -1069,4 +1069,35 @@ textfield */
|
|||
-fx-alignment: center;
|
||||
-fx-font-size: 10;
|
||||
-fx-text-fill: white;
|
||||
}
|
||||
}
|
||||
|
||||
#toggle-left {
|
||||
-fx-border-radius: 4 0 0 4;
|
||||
-fx-padding: 4 4 4 4;
|
||||
-fx-border-color: #aaa;
|
||||
-fx-border-style: solid solid solid solid;
|
||||
-fx-border-insets: 0 -2 0 0;
|
||||
-fx-background-insets: 0 -2 0 0;
|
||||
-fx-background-radius: 4 0 0 4;
|
||||
}
|
||||
|
||||
#toggle-center {
|
||||
-fx-border-radius: 0 0 0 0;
|
||||
-fx-padding: 4 4 4 4;
|
||||
-fx-border-color: #aaa;
|
||||
-fx-border-style: solid solid solid solid;
|
||||
-fx-border-insets: 0 0 0 0;
|
||||
-fx-background-insets: 0 0 0 0;
|
||||
-fx-background-radius: 0 0 0 0;
|
||||
}
|
||||
|
||||
#toggle-right {
|
||||
-fx-border-radius: 0 4 4 0;
|
||||
-fx-padding: 4 4 4 4;
|
||||
-fx-border-color: #aaa;
|
||||
-fx-border-style: solid solid solid solid;
|
||||
-fx-border-insets: 0 0 0 -2;
|
||||
-fx-background-insets: 0 0 0 -2;
|
||||
-fx-background-radius: 0 4 4 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,10 +29,13 @@ import io.bitsquare.trade.TradeStatistics;
|
|||
import javafx.beans.property.ReadOnlyObjectWrapper;
|
||||
import javafx.beans.property.SimpleStringProperty;
|
||||
import javafx.beans.property.StringProperty;
|
||||
import javafx.beans.value.ChangeListener;
|
||||
import javafx.collections.FXCollections;
|
||||
import javafx.collections.ListChangeListener;
|
||||
import javafx.geometry.Insets;
|
||||
import javafx.geometry.Pos;
|
||||
import javafx.geometry.Side;
|
||||
import javafx.scene.chart.LineChart;
|
||||
import javafx.scene.chart.NumberAxis;
|
||||
import javafx.scene.chart.XYChart;
|
||||
import javafx.scene.control.*;
|
||||
|
@ -54,17 +57,23 @@ import java.util.Date;
|
|||
public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesChartsViewModel> {
|
||||
private static final Logger log = LoggerFactory.getLogger(TradesChartsView.class);
|
||||
|
||||
private NumberAxis xAxis, yAxis;
|
||||
XYChart.Series<Number, Number> series;
|
||||
private final ListChangeListener<XYChart.Data<Number, Number>> itemsChangeListener;
|
||||
private final BSFormatter formatter;
|
||||
|
||||
private TableView<TradeStatistics> tableView;
|
||||
private ComboBox<TradeCurrency> currencyComboBox;
|
||||
private Subscription tradeCurrencySubscriber;
|
||||
private final StringProperty priceColumnLabel = new SimpleStringProperty();
|
||||
private final StringProperty volumeColumnLabel = new SimpleStringProperty();
|
||||
private CandleStickChart candleStickChart;
|
||||
private ChangeListener<Toggle> toggleChangeListener;
|
||||
private ToggleGroup toggleGroup;
|
||||
|
||||
private NumberAxis timeAxisX, priceAxisY, volumeAxisY;
|
||||
private XYChart.Series<Number, Number> priceSeries;
|
||||
private XYChart.Series<Number, Number> volumeSeries;
|
||||
private LineChart<Number, Number> volumeChart;
|
||||
private CandleStickChart priceChart;
|
||||
private final ListChangeListener<XYChart.Data<Number, Number>> itemsChangeListener;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Constructor, lifecycle
|
||||
|
@ -80,6 +89,179 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
|
|||
|
||||
@Override
|
||||
public void initialize() {
|
||||
HBox currencyHBox = createCurrencyComboBox();
|
||||
HBox toggleBarHBox = createToggleBar();
|
||||
createChart();
|
||||
final VBox tableVBox = getTableBox();
|
||||
|
||||
/* StackPane stackPane = new StackPane();
|
||||
stackPane.getChildren().addAll(priceChart, volumeChart);*/
|
||||
|
||||
root.getChildren().addAll(currencyHBox, toggleBarHBox, priceChart, tableVBox);
|
||||
|
||||
toggleChangeListener = (observable, oldValue, newValue) -> {
|
||||
if (newValue != null)
|
||||
model.setTickUnit((TradesChartsViewModel.TickUnit) newValue.getUserData());
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
currencyComboBox.setItems(model.getTradeCurrencies());
|
||||
currencyComboBox.getSelectionModel().select(model.getTradeCurrency());
|
||||
currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 25));
|
||||
currencyComboBox.setOnAction(e -> model.onSetTradeCurrency(currencyComboBox.getSelectionModel().getSelectedItem()));
|
||||
|
||||
model.items.addListener(itemsChangeListener);
|
||||
tradeCurrencySubscriber = EasyBind.subscribe(model.tradeCurrency,
|
||||
tradeCurrency -> {
|
||||
String code = tradeCurrency.getCode();
|
||||
String tradeCurrencyName = tradeCurrency.getName();
|
||||
priceSeries.setName(tradeCurrencyName);
|
||||
priceColumnLabel.set("Price (" + formatter.getCurrencyPair(code) + ")");
|
||||
volumeColumnLabel.set("Volume (" + code + ")");
|
||||
priceAxisY.setLabel(priceColumnLabel.get());
|
||||
});
|
||||
|
||||
tableView.setItems(model.tradeStatistics);
|
||||
toggleGroup.selectedToggleProperty().addListener(toggleChangeListener);
|
||||
updateChartData();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
model.items.removeListener(itemsChangeListener);
|
||||
tradeCurrencySubscriber.unsubscribe();
|
||||
currencyComboBox.setOnAction(null);
|
||||
toggleGroup.selectedToggleProperty().removeListener(toggleChangeListener);
|
||||
priceSeries.getData().clear();
|
||||
priceChart.getData().clear();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Chart
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private void createChart() {
|
||||
priceSeries = new XYChart.Series<>();
|
||||
|
||||
timeAxisX = new NumberAxis(0, model.upperBound + 1, 1);
|
||||
timeAxisX.setTickUnit(1);
|
||||
timeAxisX.setMinorTickCount(0);
|
||||
timeAxisX.setForceZeroInRange(false);
|
||||
timeAxisX.setLabel("Date/Time");
|
||||
timeAxisX.setTickLabelFormatter(getXAxisStringConverter());
|
||||
|
||||
priceAxisY = new NumberAxis();
|
||||
priceAxisY.setForceZeroInRange(false);
|
||||
priceAxisY.setAutoRanging(true);
|
||||
priceAxisY.setLabel(priceColumnLabel.get());
|
||||
priceAxisY.setTickLabelFormatter(getPriceStringConverter());
|
||||
|
||||
priceChart = new CandleStickChart(timeAxisX, priceAxisY);
|
||||
priceChart.setData(FXCollections.observableArrayList(priceSeries));
|
||||
priceChart.setAnimated(true);
|
||||
priceChart.setId("charts");
|
||||
priceChart.setMinHeight(300);
|
||||
priceChart.setPadding(new Insets(0, 30, 10, 0));
|
||||
priceChart.setToolTipStringConverter(getPriceStringConverter());
|
||||
|
||||
volumeSeries = new XYChart.Series<>();
|
||||
|
||||
volumeAxisY = new NumberAxis();
|
||||
volumeAxisY.setForceZeroInRange(false);
|
||||
volumeAxisY.setAutoRanging(true);
|
||||
volumeAxisY.setLabel(volumeColumnLabel.get());
|
||||
volumeAxisY.setTickLabelFormatter(getVolumeStringConverter());
|
||||
volumeAxisY.setSide(Side.RIGHT);
|
||||
|
||||
volumeChart = new LineChart<>(timeAxisX, volumeAxisY);
|
||||
volumeChart.setData(FXCollections.observableArrayList(volumeSeries));
|
||||
volumeChart.setAnimated(true);
|
||||
volumeChart.setId("charts");
|
||||
volumeChart.setMinHeight(300);
|
||||
volumeChart.setPadding(new Insets(0, 30, 10, 0));
|
||||
}
|
||||
|
||||
private void updateChartData() {
|
||||
priceSeries.getData().clear();
|
||||
priceChart.getData().clear();
|
||||
priceSeries = new XYChart.Series<>();
|
||||
priceSeries.getData().addAll(model.items);
|
||||
priceChart.setData(FXCollections.observableArrayList(priceSeries));
|
||||
|
||||
volumeSeries.getData().clear();
|
||||
volumeChart.getData().clear();
|
||||
volumeSeries = new XYChart.Series<>();
|
||||
volumeSeries.getData().addAll(model.volumeItems);
|
||||
volumeChart.setData(FXCollections.observableArrayList(volumeSeries));
|
||||
|
||||
timeAxisX.setTickLabelFormatter(getXAxisStringConverter());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StringConverter<Number> getXAxisStringConverter() {
|
||||
return new StringConverter<Number>() {
|
||||
@Override
|
||||
public String toString(Number object) {
|
||||
// comes as double
|
||||
long index = new Double((double) object).longValue();
|
||||
final long now = model.getTickFromTime(new Date().getTime(), model.tickUnit);
|
||||
final long tick = now - (model.upperBound - index);
|
||||
final long time = model.getTimeFromTick(tick, model.tickUnit);
|
||||
if (model.tickUnit.ordinal() <= TradesChartsViewModel.TickUnit.DAY.ordinal())
|
||||
return index % 4 == 0 ? formatter.formatDate(new Date(time)) : "";
|
||||
else
|
||||
return index % 3 == 0 ? formatter.formatTime(new Date(time)) : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number fromString(String string) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StringConverter<Number> getPriceStringConverter() {
|
||||
return new StringConverter<Number>() {
|
||||
@Override
|
||||
public String toString(Number object) {
|
||||
// comes as double
|
||||
return formatter.formatFiat(Fiat.valueOf(model.getCurrencyCode(), new Double((double) object).longValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number fromString(String string) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StringConverter<Number> getVolumeStringConverter() {
|
||||
return new StringConverter<Number>() {
|
||||
@Override
|
||||
public String toString(Number object) {
|
||||
// comes as double
|
||||
return formatter.formatFiat(Fiat.valueOf(model.getCurrencyCode(), new Double((double) object).longValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number fromString(String string) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// CurrencyComboBox
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private HBox createCurrencyComboBox() {
|
||||
currencyComboBox = new ComboBox<>();
|
||||
currencyComboBox.setPromptText("Select currency");
|
||||
currencyComboBox.setConverter(new StringConverter<TradeCurrency>() {
|
||||
|
@ -107,133 +289,49 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
|
|||
currencyHBox.setPadding(new Insets(10, -20, 0, 20));
|
||||
currencyHBox.setAlignment(Pos.CENTER_LEFT);
|
||||
currencyHBox.getChildren().addAll(currencyLabel, currencyComboBox);
|
||||
|
||||
createChart();
|
||||
|
||||
final VBox vBox = getTableBox();
|
||||
root.getChildren().addAll(currencyHBox, candleStickChart, vBox);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void activate() {
|
||||
currencyComboBox.setItems(model.getTradeCurrencies());
|
||||
currencyComboBox.getSelectionModel().select(model.getTradeCurrency());
|
||||
currencyComboBox.setVisibleRowCount(Math.min(currencyComboBox.getItems().size(), 25));
|
||||
currencyComboBox.setOnAction(e -> {
|
||||
TradeCurrency tradeCurrency = currencyComboBox.getSelectionModel().getSelectedItem();
|
||||
model.onSetTradeCurrency(tradeCurrency);
|
||||
updateChartData();
|
||||
});
|
||||
|
||||
model.items.addListener(itemsChangeListener);
|
||||
tradeCurrencySubscriber = EasyBind.subscribe(model.tradeCurrency,
|
||||
tradeCurrency -> {
|
||||
String code = tradeCurrency.getCode();
|
||||
String tradeCurrencyName = tradeCurrency.getName();
|
||||
//lineChart.setTitle("Trade history for " + tradeCurrencyName);
|
||||
series.setName(tradeCurrencyName);
|
||||
|
||||
priceColumnLabel.set("Price (" + formatter.getCurrencyPair(code) + ")");
|
||||
volumeColumnLabel.set("Volume (" + code + ")");
|
||||
yAxis.setLabel(priceColumnLabel.get());
|
||||
// xAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(xAxis, "", ""));
|
||||
});
|
||||
|
||||
tableView.setItems(model.tradeStatistics);
|
||||
updateChartData();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void deactivate() {
|
||||
model.items.removeListener(itemsChangeListener);
|
||||
tradeCurrencySubscriber.unsubscribe();
|
||||
currencyComboBox.setOnAction(null);
|
||||
}
|
||||
|
||||
|
||||
private void createChart() {
|
||||
xAxis = new NumberAxis(0, model.upperBound + 1, 1);
|
||||
xAxis.setTickUnit(1);
|
||||
// final double lowerBound = (double) model.getTimeInterval(0, model.tickUnit);
|
||||
//xAxis.setLowerBound(lowerBound);
|
||||
//final long minWith = (long) root.getWidth() / 20;
|
||||
//final double upperBound = (double) minWith;
|
||||
// xAxis.setUpperBound(upperBound);
|
||||
xAxis.setMinorTickCount(0);
|
||||
xAxis.setForceZeroInRange(false);
|
||||
//xAxis.setAutoRanging(true);
|
||||
xAxis.setLabel("Date/Time");
|
||||
xAxis.setTickLabelFormatter(getXAxisStringConverter());
|
||||
|
||||
yAxis = new NumberAxis();
|
||||
yAxis.setForceZeroInRange(false);
|
||||
yAxis.setAutoRanging(true);
|
||||
yAxis.setLabel(priceColumnLabel.get());
|
||||
yAxis.setTickLabelFormatter(getStringConverter());
|
||||
|
||||
series = new XYChart.Series<>();
|
||||
candleStickChart = new CandleStickChart(xAxis, yAxis);
|
||||
candleStickChart.setData(FXCollections.observableArrayList(series));
|
||||
candleStickChart.setAnimated(true);
|
||||
candleStickChart.setId("charts");
|
||||
candleStickChart.setMinHeight(300);
|
||||
candleStickChart.setPadding(new Insets(0, 30, 10, 0));
|
||||
candleStickChart.setToolTipStringConverter(getStringConverter());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StringConverter<Number> getXAxisStringConverter() {
|
||||
return new StringConverter<Number>() {
|
||||
@Override
|
||||
public String toString(Number object) {
|
||||
// comes as double
|
||||
long index = new Double((double) object).longValue();
|
||||
final long now = model.getTickFromTime(new Date().getTime(), model.tickUnit);
|
||||
final long tick = now - (model.upperBound - index);
|
||||
final long time = model.getTimeFromTick(tick, model.tickUnit);
|
||||
if (model.tickUnit.ordinal() <= TradesChartsViewModel.TickUnit.DAY.ordinal())
|
||||
return index % 7 == 0 ? formatter.formatDate(new Date(time)) : "";
|
||||
else
|
||||
return index % 4 == 0 ? formatter.formatTime(new Date(time)) : "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number fromString(String string) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void updateChartData() {
|
||||
series.getData().clear();
|
||||
candleStickChart.getData().clear();
|
||||
|
||||
series = new XYChart.Series<>();
|
||||
candleStickChart.setData(FXCollections.observableArrayList(series));
|
||||
series.getData().addAll(model.getItems());
|
||||
xAxis.setTickLabelFormatter(getXAxisStringConverter());
|
||||
|
||||
// xAxis.setLowerBound((double) model.getTimeInterval(0, model.tickUnit));
|
||||
//xAxis.setUpperBound((double) model.getTimeInterval((long) root.getWidth() / 20, model.tickUnit));
|
||||
return currencyHBox;
|
||||
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StringConverter<Number> getStringConverter() {
|
||||
return new StringConverter<Number>() {
|
||||
@Override
|
||||
public String toString(Number object) {
|
||||
// comes as double
|
||||
return formatter.formatFiat(Fiat.valueOf(model.getCurrencyCode(), new Double((double) object).longValue()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Number fromString(String string) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ToggleBar
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private HBox createToggleBar() {
|
||||
HBox hBox = new HBox();
|
||||
hBox.setSpacing(0);
|
||||
hBox.setPadding(new Insets(0, 0, -26, 85));
|
||||
|
||||
Label label = new Label("Interval:");
|
||||
label.setPadding(new Insets(5, 5, 0, 0));
|
||||
|
||||
toggleGroup = new ToggleGroup();
|
||||
ToggleButton month = getToggleButton("Month", TradesChartsViewModel.TickUnit.MONTH, toggleGroup, "toggle-left");
|
||||
ToggleButton week = getToggleButton("Week", TradesChartsViewModel.TickUnit.WEEK, toggleGroup, "toggle-center");
|
||||
ToggleButton day = getToggleButton("Day", TradesChartsViewModel.TickUnit.DAY, toggleGroup, "toggle-center");
|
||||
ToggleButton hour = getToggleButton("Hour", TradesChartsViewModel.TickUnit.HOUR, toggleGroup, "toggle-center");
|
||||
ToggleButton minute10 = getToggleButton("10 Minute", TradesChartsViewModel.TickUnit.MINUTE_10, toggleGroup, "toggle-center");
|
||||
ToggleButton minute = getToggleButton("Minute", TradesChartsViewModel.TickUnit.MINUTE, toggleGroup, "toggle-right");
|
||||
minute10.setSelected(true);
|
||||
hBox.getChildren().addAll(label, month, week, day, hour, minute10, minute);
|
||||
return hBox;
|
||||
}
|
||||
|
||||
private ToggleButton getToggleButton(String label, TradesChartsViewModel.TickUnit tickUnit, ToggleGroup toggleGroup, String style) {
|
||||
ToggleButton toggleButton = new ToggleButton(label);
|
||||
toggleButton.setPadding(new Insets(0, 3, 0, 3));
|
||||
toggleButton.setUserData(tickUnit);
|
||||
toggleButton.setToggleGroup(toggleGroup);
|
||||
toggleButton.setId(style);
|
||||
return toggleButton;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Table
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
private VBox getTableBox() {
|
||||
tableView = new TableView<>();
|
||||
|
||||
|
|
|
@ -52,17 +52,19 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
|||
WEEK,
|
||||
DAY,
|
||||
HOUR,
|
||||
MINUTE,
|
||||
SECOND
|
||||
MINUTE_10,
|
||||
MINUTE
|
||||
}
|
||||
|
||||
private final Preferences preferences;
|
||||
final ObjectProperty<TradeCurrency> tradeCurrency = new SimpleObjectProperty<>();
|
||||
private final HashMapChangedListener mapChangedListener;
|
||||
ObservableList<XYChart.Data<Number, Number>> items = FXCollections.observableArrayList();
|
||||
ObservableList<XYChart.Data<Number, Number>> volumeItems = FXCollections.observableArrayList();
|
||||
|
||||
private P2PService p2PService;
|
||||
final ObservableList<TradeStatistics> tradeStatistics = FXCollections.observableArrayList();
|
||||
TickUnit tickUnit = TickUnit.MINUTE;
|
||||
TickUnit tickUnit = TickUnit.MINUTE_10;
|
||||
int upperBound = 30;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -124,6 +126,10 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
|||
p2PService.removeHashMapChangedListener(mapChangedListener);
|
||||
}
|
||||
|
||||
public void setTickUnit(TickUnit tickUnit) {
|
||||
this.tickUnit = tickUnit;
|
||||
updateChartData();
|
||||
}
|
||||
|
||||
private void updateChartData() {
|
||||
items.clear();
|
||||
|
@ -155,6 +161,10 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
|||
items.addAll(candleDataList.stream()
|
||||
.map(e -> new XYChart.Data<Number, Number>(e.tick, e.open, new CandleStickExtraValues(e.close, e.high, e.low, e.average)))
|
||||
.collect(Collectors.toList()));
|
||||
|
||||
volumeItems.addAll(candleDataList.stream()
|
||||
.map(e -> new XYChart.Data<Number, Number>(e.tick, e.volume, new CandleStickExtraValues(e.close, e.high, e.low, e.average)))
|
||||
.collect(Collectors.toList()));
|
||||
}
|
||||
|
||||
CandleData getCandleData(long tick, Set<TradeStatistics> set) {
|
||||
|
@ -187,16 +197,18 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
|||
|
||||
long getTickFromTime(long tradeDateAsTime, TickUnit tickUnit) {
|
||||
switch (tickUnit) {
|
||||
case MONTH:
|
||||
return TimeUnit.MILLISECONDS.toDays(tradeDateAsTime) / 31;
|
||||
case WEEK:
|
||||
return TimeUnit.MILLISECONDS.toDays(tradeDateAsTime) * 7;
|
||||
return TimeUnit.MILLISECONDS.toDays(tradeDateAsTime) / 7;
|
||||
case DAY:
|
||||
return TimeUnit.MILLISECONDS.toDays(tradeDateAsTime);
|
||||
case HOUR:
|
||||
return TimeUnit.MILLISECONDS.toHours(tradeDateAsTime);
|
||||
case MINUTE_10:
|
||||
return TimeUnit.MILLISECONDS.toMinutes(tradeDateAsTime) / 10;
|
||||
case MINUTE:
|
||||
return TimeUnit.MILLISECONDS.toMinutes(tradeDateAsTime);
|
||||
case SECOND:
|
||||
return TimeUnit.MILLISECONDS.toSeconds(tradeDateAsTime);
|
||||
default:
|
||||
return tradeDateAsTime;
|
||||
}
|
||||
|
@ -204,16 +216,18 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
|||
|
||||
long getTimeFromTick(long tick, TickUnit tickUnit) {
|
||||
switch (tickUnit) {
|
||||
case MONTH:
|
||||
return TimeUnit.DAYS.toMillis(tick) * 31;
|
||||
case WEEK:
|
||||
return TimeUnit.DAYS.toMillis(tick) * 7;
|
||||
case DAY:
|
||||
return TimeUnit.DAYS.toMillis(tick);
|
||||
case HOUR:
|
||||
return TimeUnit.HOURS.toMillis(tick);
|
||||
case MINUTE_10:
|
||||
return TimeUnit.MINUTES.toMillis(tick) * 10;
|
||||
case MINUTE:
|
||||
return TimeUnit.MINUTES.toMillis(tick);
|
||||
case SECOND:
|
||||
return TimeUnit.SECONDS.toMillis(tick);
|
||||
default:
|
||||
return tick;
|
||||
}
|
||||
|
@ -235,10 +249,6 @@ class TradesChartsViewModel extends ActivatableViewModel {
|
|||
// Getters
|
||||
///////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public List<XYChart.Data<Number, Number>> getItems() {
|
||||
return items;
|
||||
}
|
||||
|
||||
public String getCurrencyCode() {
|
||||
return tradeCurrency.get().getCode();
|
||||
}
|
||||
|
|
|
@ -36,11 +36,15 @@ import javafx.scene.control.Tooltip;
|
|||
import javafx.scene.layout.Region;
|
||||
import javafx.scene.shape.Line;
|
||||
import javafx.util.StringConverter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Candle node used for drawing a candle
|
||||
*/
|
||||
public class Candle extends Group {
|
||||
private static final Logger log = LoggerFactory.getLogger(Candle.class);
|
||||
|
||||
private final TooltipContent tooltipContent;
|
||||
private Line highLowLine = new Line();
|
||||
private Region bar = new Region();
|
||||
|
@ -48,6 +52,7 @@ public class Candle extends Group {
|
|||
private String dataStyleClass;
|
||||
private boolean openAboveClose = true;
|
||||
private Tooltip tooltip = new Tooltip();
|
||||
private double closeOffset;
|
||||
|
||||
Candle(String seriesStyleClass, String dataStyleClass, StringConverter<Number> toolTipStringConverter) {
|
||||
setAutoSizeChildren(false);
|
||||
|
@ -67,6 +72,7 @@ public class Candle extends Group {
|
|||
}
|
||||
|
||||
public void update(double closeOffset, double highOffset, double lowOffset, double candleWidth) {
|
||||
this.closeOffset = closeOffset;
|
||||
openAboveClose = closeOffset > 0;
|
||||
updateStyleClasses();
|
||||
highLowLine.setStartY(highOffset);
|
||||
|
@ -75,22 +81,27 @@ public class Candle extends Group {
|
|||
candleWidth = bar.prefWidth(-1);
|
||||
}
|
||||
if (openAboveClose) {
|
||||
bar.resizeRelocate(-candleWidth / 2, 0, candleWidth, closeOffset);
|
||||
bar.resizeRelocate(-candleWidth / 2, 0, candleWidth, Math.max(5, closeOffset));
|
||||
} else {
|
||||
bar.resizeRelocate(-candleWidth / 2, closeOffset, candleWidth, closeOffset * -1);
|
||||
bar.resizeRelocate(-candleWidth / 2, closeOffset, candleWidth, Math.max(5, closeOffset * -1));
|
||||
}
|
||||
}
|
||||
|
||||
public void updateTooltip(double open, double close, double high, double low) {
|
||||
tooltipContent.update(open, close, high, low);
|
||||
//tooltip.setText("Open: " + open + "\nClose: " + close + "\nHigh: " + high + "\nLow: " + low);
|
||||
}
|
||||
|
||||
private void updateStyleClasses() {
|
||||
getStyleClass().setAll("candlestick-candle", seriesStyleClass, dataStyleClass);
|
||||
|
||||
String style = openAboveClose ? "open-above-close" : "close-above-open";
|
||||
if (closeOffset == 0)
|
||||
style = "empty";
|
||||
|
||||
highLowLine.getStyleClass().setAll("candlestick-line", seriesStyleClass, dataStyleClass,
|
||||
openAboveClose ? "open-above-close" : "close-above-open");
|
||||
style);
|
||||
|
||||
bar.getStyleClass().setAll("candlestick-bar", seriesStyleClass, dataStyleClass,
|
||||
openAboveClose ? "open-above-close" : "close-above-open");
|
||||
style);
|
||||
}
|
||||
}
|
|
@ -58,6 +58,7 @@ import java.util.List;
|
|||
*/
|
||||
public class CandleStickChart extends XYChart<Number, Number> {
|
||||
private static final Logger log = LoggerFactory.getLogger(CandleStickChart.class);
|
||||
|
||||
private StringConverter<Number> toolTipStringConverter;
|
||||
private Path seriesPath;
|
||||
|
||||
|
@ -71,11 +72,6 @@ public class CandleStickChart extends XYChart<Number, Number> {
|
|||
*/
|
||||
public CandleStickChart(Axis<Number> xAxis, Axis<Number> yAxis) {
|
||||
super(xAxis, yAxis);
|
||||
getStylesheets().add(
|
||||
CandleStickChart.class.getResource("CandleStickChart.css").toExternalForm());
|
||||
setAnimated(false);
|
||||
xAxis.setAnimated(false);
|
||||
yAxis.setAnimated(false);
|
||||
}
|
||||
|
||||
// -------------- METHODS ------------------------------------------------------------------------------------------
|
||||
|
@ -146,6 +142,7 @@ public class CandleStickChart extends XYChart<Number, Number> {
|
|||
@Override
|
||||
protected void dataItemAdded(XYChart.Series<Number, Number> series, int itemIndex, XYChart.Data<Number, Number> item) {
|
||||
Node candle = createCandle(getData().indexOf(series), item, itemIndex);
|
||||
|
||||
if (shouldAnimate()) {
|
||||
candle.setOpacity(0);
|
||||
getPlotChildren().add(candle);
|
||||
|
@ -157,9 +154,8 @@ public class CandleStickChart extends XYChart<Number, Number> {
|
|||
getPlotChildren().add(candle);
|
||||
}
|
||||
// always draw average line on top
|
||||
if (series.getNode() != null) {
|
||||
series.getNode().toFront();
|
||||
}
|
||||
if (seriesPath != null)
|
||||
seriesPath.toFront();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Add table
Reference in a new issue