Skip to content

Commit

Permalink
Merge pull request #473 from Drakkar-Software/dev
Browse files Browse the repository at this point in the history
Update master
  • Loading branch information
Herklos authored May 30, 2021
2 parents 2b85ad8 + d33e8c1 commit 2ec53cd
Show file tree
Hide file tree
Showing 71 changed files with 1,518 additions and 139 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,24 +47,24 @@ async def test_slow_downtrend(self):
# market: -44.248234106962656
# market: -34.87003936300901
# market: -45.18518518518518
await self.run_test_slow_downtrend(-9.26, -29.321, -16.191, -15.932)
await self.run_test_slow_downtrend(-9.26, -29.321, -16.191, -15.864)

async def test_sharp_downtrend(self):
# market: -30.271723049610415
# market: -32.091097308488614
await self.run_test_sharp_downtrend(-7.577, -22.088)
await self.run_test_sharp_downtrend(-7.578, -22.09)

async def test_flat_markets(self):
# market: 5.052093571849795
# market: 3.4840425531915002
# market: -12.732688011913623
# market: -34.64150943396227
await self.run_test_flat_markets(2.429, 8.981, -5.819, -18.679)
await self.run_test_flat_markets(2.429, 8.981, -5.819, -18.693)

async def test_slow_uptrend(self):
# market: 32.524679029957184
# market: 6.25
await self.run_test_slow_uptrend(4.95, 5.35)
await self.run_test_slow_uptrend(4.95, 5.348)

async def test_sharp_uptrend(self):
# market: 24.56254050550875
Expand All @@ -73,7 +73,7 @@ async def test_sharp_uptrend(self):

async def test_up_then_down(self):
# market: 1.1543668450702853
await self.run_test_up_then_down(8.714)
await self.run_test_up_then_down(8.713)


async def test_default_run(strategy_tester):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,31 +40,31 @@ class TechnicalAnalysisStrategyEvaluatorTest(abstract_strategy_test.AbstractStra

async def test_default_run(self):
# market: -12.052505966587105
await self.run_test_default_run(-2.717)
await self.run_test_default_run(-2.718)

async def test_slow_downtrend(self):
# market: -12.052505966587105
# market: -15.195702225633141
# market: -29.12366137549725
# market: -32.110091743119256
await self.run_test_slow_downtrend(-2.717, -4.584, -9.798, -12.499)
await self.run_test_slow_downtrend(-2.718, -4.584, -9.798, -12.562)

async def test_sharp_downtrend(self):
# market: -26.07183938094741
# market: -32.1654501216545
await self.run_test_sharp_downtrend(-19.514, -13.323)
await self.run_test_sharp_downtrend(-19.514, -13.322)

async def test_flat_markets(self):
# market: -10.560669456066947
# market: -3.401191658391241
# market: -5.7854560064282765
# market: -8.067940552016978
await self.run_test_flat_markets(-0.811, 0.733, -7.592, 8.305)
await self.run_test_flat_markets(-0.811, 0.733, -7.592, 8.319)

async def test_slow_uptrend(self):
# market: 17.203948364436457
# market: 16.19613670133728
await self.run_test_slow_uptrend(3.895, 16.903)
await self.run_test_slow_uptrend(3.895, 16.862)

async def test_sharp_uptrend(self):
# market: 30.881852230166828
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,19 +47,19 @@ async def test_slow_downtrend(self):
# market: -15.195702225633141
# market: -29.12366137549725
# market: -32.110091743119256
await self.run_test_slow_downtrend(-2.592, -2.347, -17.393, -15.889)
await self.run_test_slow_downtrend(-2.592, -2.347, -17.393, -15.761)

async def test_sharp_downtrend(self):
# market: -26.07183938094741
# market: -32.1654501216545
await self.run_test_sharp_downtrend(-8.537, -10.317)
await self.run_test_sharp_downtrend(-8.538, -10.3)

async def test_flat_markets(self):
# market: -10.560669456066947
# market: -3.401191658391241
# market: -5.7854560064282765
# market: -8.067940552016978
await self.run_test_flat_markets(0.953, 1.097, -8.131, -7.033)
await self.run_test_flat_markets(0.953, 1.097, -8.126, -7.038)

async def test_slow_uptrend(self):
# market: 17.203948364436457
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import tentacles.Services.Interfaces.web_interface.login as login
import tentacles.Services.Interfaces.web_interface.util as util
import tentacles.Services.Interfaces.web_interface.models as models
import octobot_services.interfaces.util as interfaces_util


@advanced_controllers.advanced.route("/tentacles")
Expand All @@ -34,10 +35,20 @@ def _handle_package_operation(update_type):
request_data = flask.request.get_json()
success = False
if request_data:
path_or_url, action = next(iter(request_data.items()))
path_or_url = path_or_url.strip()
version = None
url_key = "url"
if url_key in request_data:
path_or_url = request_data[url_key]
version = request_data.get("version", None)
action = "register_and_install"
else:
path_or_url, action = next(iter(request_data.items()))
path_or_url = request_data.strip()
if action == "register_and_install":
installation_result = models.install_packages(path_or_url)
installation_result = models.install_packages(
path_or_url,
version,
authenticator=interfaces_util.get_bot_api().get_community_auth())
if installation_result:
return util.get_rest_reply(flask.jsonify(installation_result))
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@ <h1>Strategy optimizer
</h1>
</div>
<div class="card-body" id="paramSettings" update-url="{{ url_for('advanced.strategy_optimizer', update_type='run_params') }}">
<div class="alert alert-info" role="alert">
<p class="mb-0">
For now the strategy optimizer can only be used with the daily trading mode as is helps to
identify better evaluators configurations and this trading mode is the only one supporting
custom evaluators setups.
</p>
</div>
<div class="input-group">
<div class="input-group-prepend mb-3">
<label class="input-group-text" for="tradingModeSelect">
Expand Down
5 changes: 4 additions & 1 deletion Services/Interfaces/web_interface/controllers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@
community_login,
community_logout,
)
from tentacles.Services.Interfaces.web_interface.controllers.community import (
community_metrics,
)
from tentacles.Services.Interfaces.web_interface.controllers.backtesting import (
data_collector,
)
Expand Down Expand Up @@ -86,7 +89,6 @@
)



__all__ = [
"CommunityLoginForm",
"community_login",
Expand All @@ -99,6 +101,7 @@
"commands",
"about",
"community",
"community_metrics",
"profile",
"profiles_management",
"config",
Expand Down
35 changes: 32 additions & 3 deletions Services/Interfaces/web_interface/controllers/community.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

import flask

import octobot.constants as constants
import octobot_commons.authentication as authentication
import octobot_services.interfaces.util as interfaces_util
import tentacles.Services.Interfaces.web_interface as web_interface
import tentacles.Services.Interfaces.web_interface.login as login
import tentacles.Services.Interfaces.web_interface.models as models
Expand All @@ -24,9 +27,35 @@
@web_interface.server_instance.route("/community")
@login.login_required_when_activated
def community():
can_get_metrics = models.can_get_community_metrics()
community_metrics = models.get_community_metrics_to_display() if can_get_metrics else None
authenticator = interfaces_util.get_bot_api().get_community_auth()
logged_in_email = None
use_preview = not authenticator.can_authenticate()
try:
logged_in_email = authenticator.get_logged_in_email()
except (authentication.AuthenticationRequired, authentication.UnavailableError):
pass
except Exception as e:
flask.flash(f"Error when contacting the community server: {e}", "error")
if logged_in_email is None and not use_preview:
return flask.redirect('community_login')
tentacles_packages = models.get_account_tentacles_packages(authenticator) if logged_in_email else []
default_image = flask.url_for('static', filename="img/community/tentacles_packages_previews/octobot.png")
return flask.render_template('community.html',
use_preview=use_preview,
preview_tentacles_packages=models.get_preview_tentacles_packages(flask.url_for),
current_logged_in_email=logged_in_email,
tentacles_packages=tentacles_packages,
current_bots_stats=models.get_current_octobots_stats(),
community_url=constants.OCTOBOT_COMMUNITY_URL,
default_tentacles_package_image=default_image)


@web_interface.server_instance.route("/community_metrics")
@login.login_required_when_activated
def community_metrics():
can_get_metrics = models.can_get_community_metrics()
display_metrics = models.get_community_metrics_to_display() if can_get_metrics else None
return flask.render_template('community_metrics.html',
can_get_metrics=can_get_metrics,
community_metrics=community_metrics
community_metrics=display_metrics
)
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
import wtforms.fields.html5

import octobot.constants as constants
import octobot.community as community
import octobot_commons.authentication as authentication
import octobot_services.interfaces.util as interfaces_util
import tentacles.Services.Interfaces.web_interface as web_interface
import tentacles.Services.Interfaces.web_interface.login as login
import tentacles.Services.Interfaces.web_interface.models as models


@web_interface.server_instance.route('/community_login', methods=['GET', 'POST'])
Expand All @@ -31,7 +32,7 @@ def community_login():
logged_in_email = form = None
try:
logged_in_email = authenticator.get_logged_in_email()
except community.AuthenticationRequired:
except authentication.AuthenticationRequired:
pass
except Exception as e:
flask.flash(f"Error when contacting the community server: {e}", "error")
Expand All @@ -42,13 +43,15 @@ def community_login():
authenticator.login(form.email.data, form.password.data)
logged_in_email = form.email.data
flask.flash(f"Authenticated as {form.email.data}", "success")
except community.FailedAuthentication:
return flask.redirect('community')
except authentication.FailedAuthentication:
flask.flash(f"Invalid email or password", "error")
except Exception as e:
flask.flash(f"Error during authentication: {e}", "error")
return flask.render_template('community_login.html',
form=form,
current_logged_in_email=logged_in_email,
current_bots_stats=models.get_current_octobots_stats(),
community_url=constants.OCTOBOT_COMMUNITY_URL)


Expand Down
6 changes: 6 additions & 0 deletions Services/Interfaces/web_interface/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
from tentacles.Services.Interfaces.web_interface.models.community import (
get_community_metrics_to_display,
can_get_community_metrics,
get_account_tentacles_packages,
get_preview_tentacles_packages,
get_current_octobots_stats,
)
from tentacles.Services.Interfaces.web_interface.models.configuration import (
get_evaluators_tentacles_startup_activation,
Expand Down Expand Up @@ -160,6 +163,9 @@
"update_bot",
"get_community_metrics_to_display",
"can_get_community_metrics",
"get_account_tentacles_packages",
"get_preview_tentacles_packages",
"get_current_octobots_stats",
"get_evaluators_tentacles_startup_activation",
"get_trading_tentacles_startup_activation",
"get_tentacle_documentation",
Expand Down
32 changes: 31 additions & 1 deletion Services/Interfaces/web_interface/models/community.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@
#
# You should have received a copy of the GNU Lesser General Public
# License along with this library.

import octobot_services.interfaces.util as interfaces_util
import octobot.community as octobot_community

Expand All @@ -24,3 +23,34 @@ def get_community_metrics_to_display():

def can_get_community_metrics():
return octobot_community.can_read_metrics(interfaces_util.get_edited_config(dict_only=False))


def get_account_tentacles_packages(authenticator):
packages = authenticator.get_packages()
return [octobot_community.CommunityTentaclesPackage.from_community_dict(data) for data in packages]


def get_preview_tentacles_packages(url_for):
c1 = octobot_community.CommunityTentaclesPackage(
"AI candles analyser",
"Tentacles packages offering artificial intelligence analysis tools based on candles shapes.",
None, True,
[url_for("static", filename="img/community/tentacles_packages_previews/octobot.png")], None, None, None)
c1.uninstalled = False
c2 = octobot_community.CommunityTentaclesPackage(
"Telegram portfolio management",
"Manage your portfolio directly from the telegram interface.",
None, False,
[url_for("static", filename="img/community/tentacles_packages_previews/telegram.png")], None, None, None)
c2.uninstalled = False
c3 = octobot_community.CommunityTentaclesPackage(
"Mobile first web interface",
"Use a mobile oriented interface for your OctoBot.",
None, True,
[url_for("static", filename="img/community/tentacles_packages_previews/mobile.png")], None, None, None)
c3.uninstalled = True
return [c1, c2, c3]


def get_current_octobots_stats():
return interfaces_util.run_in_bot_async_executor(octobot_community.get_current_octobots_stats())
25 changes: 17 additions & 8 deletions Services/Interfaces/web_interface/models/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,9 @@ def get_tentacle_documentation(name, media_url, missing_tentacles: set = None):
f"This is probably an issue with the {name} tentacle matadata.json file, please "
f"make sure this file is accurate and is referring {name} in the 'tentacles' list.")
return ""

except TypeError:
# can happen when tentacles metadata.json are invalid
return ""

def _get_strategy_activation_state(with_trading_modes, media_url, missing_tentacles: set):
import tentacles.Trading.Mode as modes
Expand Down Expand Up @@ -167,6 +169,10 @@ def _add_to_missing_tentacles_if_missing(tentacle_name: str, missing_tentacles:
tentacles_manager_api.get_tentacle_version(tentacle_name)
except KeyError:
missing_tentacles.add(tentacle_name)
except AttributeError:
_get_logger().error(f"Missing tentacles data for {tentacle_name}. This is likely due to an error in the "
f"associated metadata.json file.")
missing_tentacles.add(tentacle_name)


def _get_tentacle_packages():
Expand Down Expand Up @@ -241,13 +247,16 @@ def _add_tentacles_activation_desc_for_group(activation_by_group, tentacles_acti
root_element, media_url, missing_tentacles: set):
for tentacle_class_name, activated in tentacles_activation[root_element].items():
startup_val = startup_tentacles_activation[root_element][tentacle_class_name]
tentacle, group = _get_tentacle_activation_desc(tentacle_class_name, activated, startup_val, media_url,
missing_tentacles)
if group in activation_by_group:
activation_by_group[group].append(tentacle)
else:
activation_by_group[group] = [tentacle]

try:
tentacle, group = _get_tentacle_activation_desc(tentacle_class_name, activated, startup_val, media_url,
missing_tentacles)
if group in activation_by_group:
activation_by_group[group].append(tentacle)
else:
activation_by_group[group] = [tentacle]
except AttributeError:
# can happen when tentacles metadata.json are invalid
pass

def get_tentacles_activation_desc_by_group(media_url, missing_tentacles: set):
tentacles_activation = tentacles_manager_api.get_tentacles_activation(interfaces_util.get_edited_tentacles_config())
Expand Down
Loading

0 comments on commit 2ec53cd

Please sign in to comment.