diff --git a/Services/Interfaces/web_interface/advanced_templates/advanced_layout.html b/Services/Interfaces/web_interface/advanced_templates/advanced_layout.html
index 4af30475b..a4294c235 100644
--- a/Services/Interfaces/web_interface/advanced_templates/advanced_layout.html
+++ b/Services/Interfaces/web_interface/advanced_templates/advanced_layout.html
@@ -47,7 +47,7 @@
{% if IS_DEMO or IS_CLOUD or IS_ALLOWING_TRACKING%}
{% endif %}
diff --git a/Services/Interfaces/web_interface/controllers/home.py b/Services/Interfaces/web_interface/controllers/home.py
index 2a015ff59..00e0c09a6 100644
--- a/Services/Interfaces/web_interface/controllers/home.py
+++ b/Services/Interfaces/web_interface/controllers/home.py
@@ -87,6 +87,9 @@ def home():
sandbox_exchanges=sandbox_exchanges,
display_ph_launch=display_ph_launch,
is_launching=is_launching,
+ latest_release_url=f"{octobot_commons.constants.GITHUB_BASE_URL}/"
+ f"{octobot_commons.constants.GITHUB_ORGANISATION}/"
+ f"{constants.PROJECT_NAME}/releases/latest",
)
else:
return flask.redirect(flask.url_for("terms"))
diff --git a/Services/Interfaces/web_interface/models/dashboard.py b/Services/Interfaces/web_interface/models/dashboard.py
index 4258a4757..3a227aa80 100644
--- a/Services/Interfaces/web_interface/models/dashboard.py
+++ b/Services/Interfaces/web_interface/models/dashboard.py
@@ -71,7 +71,10 @@ def format_trades(dict_trade_history):
float(dict_trade[trading_enums.ExchangeConstantsOrderColumns.PRICE.value]))
trades[trade_description_key].append(
f"{trade_type.name.replace('_', ' ')}: "
- f"{dict_trade[trading_enums.ExchangeConstantsOrderColumns.AMOUNT.value]}")
+ f"{dict_trade[trading_enums.ExchangeConstantsOrderColumns.AMOUNT.value]} "
+ f"{dict_trade[trading_enums.ExchangeConstantsOrderColumns.QUANTITY_CURRENCY.value]} "
+ f"at {dict_trade[trading_enums.ExchangeConstantsOrderColumns.PRICE.value]} "
+ f"{dict_trade[trading_enums.ExchangeConstantsOrderColumns.MARKET.value]}")
trades[trade_order_side_key].append(trade_side.value)
return trades
diff --git a/Services/Interfaces/web_interface/models/trading.py b/Services/Interfaces/web_interface/models/trading.py
index 63c027455..9bfed793a 100644
--- a/Services/Interfaces/web_interface/models/trading.py
+++ b/Services/Interfaces/web_interface/models/trading.py
@@ -87,7 +87,8 @@ def get_exchanges_load():
"load": trading_api.get_currently_handled_pair_with_time_frame(exchange_manager),
"max_load": trading_api.get_max_handled_pair_with_time_frame(exchange_manager),
"overloaded": trading_api.is_overloaded(exchange_manager),
- "has_websocket": trading_api.get_has_websocket(exchange_manager)
+ "has_websocket": trading_api.get_has_websocket(exchange_manager),
+ "has_reached_websocket_limit": trading_api.get_has_reached_websocket_limit(exchange_manager)
}
for exchange_manager in interfaces_util.get_exchange_managers()
}
diff --git a/Services/Interfaces/web_interface/static/css/style.css b/Services/Interfaces/web_interface/static/css/style.css
index 6cd7a1b75..3a1eab767 100644
--- a/Services/Interfaces/web_interface/static/css/style.css
+++ b/Services/Interfaces/web_interface/static/css/style.css
@@ -21,6 +21,8 @@
:root {
--mdb-body-font-family: DM Sans, sans-serif;
--local-secondary-bg-text-color: #0f1237; /* same as dark mdb-primary */
+ --local-price-chart-sell-color: #F65A33;
+ --local-price-chart-stop-color: #FFA500;
}
:root[data-mdb-theme=light] {
@@ -72,14 +74,22 @@
--mdb-card-long-border-color: var(--mdb-secondary);
--mdb-card-short-border-color: var(--mdb-orange);
--mdb-card-very-short-border-color: var(--mdb-red);
+ --mdb-card-bg: var(--mdb-bg);
+ --mdb-card-color: var(--mdb-primary);
+ --mdb-surface-bg: var(--mdb-bg);
/* navbar */
--mdb-navbar-bg: var(--mdb-bg);
--mdb-navbar-brand-color: var(--mdb-primary);
- --mdb-card-bg: var(--mdb-bg);
- --mdb-card-color: var(--mdb-primary);
- --mdb-surface-bg: var(--mdb-bg);
+ /* local */
+ /* config cards */
+ --local-config-card--border-width: 0px;
+
+ /* price charts */
+ --local-price-chart-buy-color: #6cb596;
+ --local-price-chart-candle-sell-color: var(--local-price-chart-sell-color);
+ --local-price-chart-candle-buy-color: #6cb596;
}
:root[data-mdb-theme=dark] {
@@ -130,14 +140,22 @@
--mdb-card-long-border-color: var(--mdb-secondary);
--mdb-card-short-border-color: var(--mdb-orange);
--mdb-card-very-short-border-color: var(--mdb-red);
+ --mdb-card-bg: var(--mdb-secondary);
+ --mdb-card-color: var(--mdb-primary);
+ --mdb-surface-bg: var(--mdb-bg-500);
/* navbar */
--mdb-navbar-bg: var(--mdb-bg);
--mdb-navbar-brand-color: var(--mdb-primary);
- --mdb-card-bg: var(--mdb-secondary);
- --mdb-card-color: var(--mdb-primary);
- --mdb-surface-bg: var(--mdb-bg-500);
+ /* local */
+ /* config cards */
+ --local-config-card--border-width: 1px;
+
+ /* price charts */
+ --local-price-chart-buy-color: #6cb596;
+ --local-price-chart-candle-sell-color: var(--local-price-chart-sell-color);
+ --local-price-chart-candle-buy-color: #65e7cf;
}
/* Fix incompatibility with bootstrap 4 */
@@ -459,6 +477,10 @@ footer.page-footer {
flex-basis: inherit !important;
}
+.config-card {
+ border: var(--local-config-card--border-width) solid rgba(var(--mdb-primary-rgb), 0.3);
+}
+
.community-bot-stats-label {
font-weight: bold;
font-size: x-large;
@@ -563,7 +585,7 @@ footer.page-footer {
/* Theme */
/* Elegant */
.card-body.candle-graph {
- min-height: 30.625rem;
+ height: 30.625rem;
background-color: inherit;
}
diff --git a/Services/Interfaces/web_interface/static/js/common/candlesticks.js b/Services/Interfaces/web_interface/static/js/common/candlesticks.js
index 38913487d..0fe75b880 100644
--- a/Services/Interfaces/web_interface/static/js/common/candlesticks.js
+++ b/Services/Interfaces/web_interface/static/js/common/candlesticks.js
@@ -118,9 +118,11 @@ function get_watched_symbol_price_graph(element, callback=undefined, no_data_cal
});
}
-const stop_color = "#FFA500";
-const sell_color = "#F65A33";
-const buy_color = isDarkTheme() ? '#299a39' : "#009900";
+const stop_color = getComputedStyle(document.body).getPropertyValue('--local-price-chart-stop-color');
+const sell_color = getComputedStyle(document.body).getPropertyValue('--local-price-chart-sell-color');
+const buy_color = getComputedStyle(document.body).getPropertyValue('--local-price-chart-buy-color');
+const candle_sell_color = getComputedStyle(document.body).getPropertyValue('----local-price-chart-candle-sell-color');
+const candle_buy_color = getComputedStyle(document.body).getPropertyValue('--local-price-chart-candle-buy-color');
function create_candlesticks(candles){
const data_time = candles["time"];
@@ -132,9 +134,9 @@ function create_candlesticks(candles){
return {
x: data_time,
close: data_close,
- decreasing: {line: {color: sell_color}},
+ decreasing: {line: {color: candle_sell_color}},
high: data_high,
- increasing: {line: {color: buy_color}},
+ increasing: {line: {color: candle_buy_color}},
line: {color: 'rgba(31,119,180,1)'},
low: data_low,
open: data_open,
@@ -187,22 +189,23 @@ function create_trades(trades, trader){
const data_trade_description = trades["trade_description"];
const data_order_side = trades["order_side"];
- const marker_size = trader === "Simulator" ? 14 : 16;
- const marker_opacity = trader === "Simulator" ? 0.5 : 0.65;
- const border_line_color = "#b6b8c3";
+ const marker_size = 16;
+ const marker_opacity = 0.9;
+ const border_line_color = getTextColor();
const colors = [];
$.each(data_order_side, function (index, value) {
colors.push(_getOrderColor(trades["trade_description"][index], value));
});
- const line_with = trader === "Simulator" ? 0 : 1;
+ const line_with = isDarkTheme() ? 1 : 0.2;
return {
x: data_time,
y: data_price,
mode: 'markers',
- name: trader,
+ name: "",
text: data_trade_description,
+ hovertemplate: `%{text}
%{x}`,
marker: {
color: colors,
size: marker_size,
diff --git a/Services/Interfaces/web_interface/static/js/common/exchange_accounts.js b/Services/Interfaces/web_interface/static/js/common/exchange_accounts.js
index 5ac82f499..9554a72bb 100644
--- a/Services/Interfaces/web_interface/static/js/common/exchange_accounts.js
+++ b/Services/Interfaces/web_interface/static/js/common/exchange_accounts.js
@@ -93,7 +93,7 @@ function register_exchanges_checks(check_existing_accounts){
const check_account = (exchangeCard, source, newValue) => {
const exchange = exchangeCard.find(".card-body").attr("name");
- if(exchange !== config_default_value){
+ if(exchange !== config_default_value && exchangeCard.find("#exchange_api-key").length > 0){
const apiKey = source.attr("id") === "exchange_api-key" ? newValue : exchangeCard.find("#exchange_api-key").editable('getValue', true).trim();
const apiSecret = source.attr("id") === "exchange_api-secret" ? newValue : exchangeCard.find("#exchange_api-secret").editable('getValue', true).trim();
const apiPassword = source.attr("id") === "exchange_api-password" ? newValue : exchangeCard.find("#exchange_api-password").editable('getValue', true).trim();
diff --git a/Services/Interfaces/web_interface/static/js/common/tracking.js b/Services/Interfaces/web_interface/static/js/common/tracking.js
index 91210b00e..6e8419e96 100644
--- a/Services/Interfaces/web_interface/static/js/common/tracking.js
+++ b/Services/Interfaces/web_interface/static/js/common/tracking.js
@@ -2,17 +2,20 @@
$(document).ready(function() {
const getUserEmail = () => {
- return getUserDetails().email
+ return getUserDetails().email || "";
}
const getUserDetails = () => {
+ if (_USER_DETAILS.email === ""){
+ // do not erase email if unset
+ delete _USER_DETAILS.email;
+ }
return _USER_DETAILS
}
const updateUserDetails = () => {
posthog.capture(
- getUserEmail(),
- event='update_user_details',
+ 'up_user_details',
properties={
'$set': getUserDetails(),
}
@@ -21,11 +24,19 @@ $(document).ready(function() {
const shouldUpdateUserDetails = () => {
const currentProperties = posthog.get_property('$stored_person_properties');
- return (
- getUserEmail() !== ""
- && isDefined(currentProperties)
- && JSON.stringify(currentProperties) !== JSON.stringify(getUserDetails())
- )
+ if(currentProperties === undefined){
+ return true;
+ }
+ if(isDefined(currentProperties)){
+ const currentDetails = getUserDetails();
+ if(currentDetails.email === undefined){
+ // compare without email (otherwise result is always different as no email is currently set)
+ const localProperties = JSON.parse(JSON.stringify(currentProperties));
+ delete localProperties.email
+ return JSON.stringify(localProperties) !== JSON.stringify(getUserDetails());
+ }
+ }
+ return JSON.stringify(currentProperties) !== JSON.stringify(getUserDetails());
}
const shouldReset = (newEmail) => {
diff --git a/Services/Interfaces/web_interface/templates/components/config/currency_card.html b/Services/Interfaces/web_interface/templates/components/config/currency_card.html
index ea9be644c..b497bf012 100644
--- a/Services/Interfaces/web_interface/templates/components/config/currency_card.html
+++ b/Services/Interfaces/web_interface/templates/components/config/currency_card.html
@@ -8,7 +8,7 @@