Skip to content

Commit

Permalink
Merge pull request #2221 from Drakkar-Software/dev
Browse files Browse the repository at this point in the history
Master merge
  • Loading branch information
GuillaumeDSM authored Feb 6, 2023
2 parents a61102a + 0293501 commit 4c968f9
Show file tree
Hide file tree
Showing 16 changed files with 219 additions and 28 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

*It is strongly advised to perform an update of your tentacles after updating OctoBot. (start.py tentacles --install --all)*

## [0.4.37] - 2023-02-06
### Added
- Configurations: add limits
### Fixed
- Futures trading: portfolio and cancel order issues

## [0.4.36] - 2023-01-29
### Added
- Automations: initialize automations
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# OctoBot [0.4.36](https://octobot.click/gh-changelog)
# OctoBot [0.4.37](https://octobot.click/gh-changelog)
[![PyPI](https://img.shields.io/pypi/v/OctoBot.svg)](https://octobot.click/gh-pypi)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/e07fb190156d4efb8e7d07aaa5eff2e1)](https://app.codacy.com/gh/Drakkar-Software/OctoBot?utm_source=github.com&utm_medium=referral&utm_content=Drakkar-Software/OctoBot&utm_campaign=Badge_Grade_Dashboard)[![Downloads](https://pepy.tech/badge/octobot/month)](https://pepy.tech/project/octobot)
[![Dockerhub](https://img.shields.io/docker/pulls/drakkarsoftware/octobot.svg)](https://octobot.click/gh-dockerhub)
Expand Down
2 changes: 1 addition & 1 deletion octobot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,5 @@

PROJECT_NAME = "OctoBot"
AUTHOR = "Drakkar-Software"
VERSION = "0.4.36" # major.minor.revision
VERSION = "0.4.37" # major.minor.revision
LONG_VERSION = f"{VERSION}"
9 changes: 8 additions & 1 deletion octobot/automation/automation.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import octobot.automation.bases.abstract_trigger_event as abstract_trigger_event
import octobot.automation.bases.abstract_condition as abstract_condition
import octobot.automation.bases.abstract_action as abstract_action
import octobot.constants as constants
import octobot.errors as errors


class AutomationDetails:
Expand Down Expand Up @@ -61,7 +63,10 @@ async def initialize(self) -> None:
"""
Triggers producers and consumers creation
"""
await self.restart()
if constants.ENABLE_AUTOMATIONS:
await self.restart()
else:
self.logger.info("Automations are disabled")

@classmethod
async def get_raw_config_and_user_inputs(
Expand All @@ -76,6 +81,8 @@ async def get_raw_config_and_user_inputs(
return tentacle_config, list(user_input.to_dict() for user_input in user_inputs.values())

async def restart(self):
if not constants.ENABLE_AUTOMATIONS:
raise errors.DisabledError("Automations are disabled")
await self.stop()
self.automations_config = tentacles_manager_api.get_tentacle_config(self.tentacles_setup_config,
self.__class__)
Expand Down
18 changes: 10 additions & 8 deletions octobot/automation/bases/abstract_trigger_event.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
# You should have received a copy of the GNU General Public
# License along with OctoBot. If not, see <https://www.gnu.org/licenses/>.
import abc
import time

import octobot.automation.bases.automation_step as automation_step

Expand All @@ -23,7 +24,8 @@ def __init__(self):
super(AbstractTriggerEvent, self).__init__()
self.should_stop = False
self.trigger_only_once = False
self._triggered_already = False
self.max_trigger_frequency = 0
self._last_trigger_time = 0

async def stop(self):
self.should_stop = True
Expand All @@ -37,10 +39,10 @@ async def next_event(self):
async for event in self.next_event():
# triggered when an event occurs
"""
self._triggered_already = False
while not self.should_stop and not (self.trigger_only_once and self._triggered_already):
yield await self._get_next_event()
self._triggered_already = True



self._last_trigger_time = 0
while not self.should_stop and not (self.trigger_only_once and self._last_trigger_time != 0):
new_event = await self._get_next_event()
trigger_time = time.time()
if not self.max_trigger_frequency or (trigger_time - self._last_trigger_time > self.max_trigger_frequency):
yield new_event
self._last_trigger_time = time.time()
1 change: 1 addition & 0 deletions octobot/backtesting/octobot_backtesting.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ cdef class OctoBotBacktesting:
cdef public object futures_contract_type
cdef public bint enable_storage
cdef public bint run_on_all_available_time_frames
cdef bint _has_started

cpdef object memory_leak_checkup(self, list to_check_elements)
cpdef object check_remaining_objects(self)
Expand Down
22 changes: 21 additions & 1 deletion octobot/backtesting/octobot_backtesting.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@

import octobot.logger as logger
import octobot.storage as storage
import octobot.limits as limits
import octobot.constants as constants
import octobot.errors as errors
import octobot.databases_util as databases_util


Expand Down Expand Up @@ -82,8 +85,11 @@ def __init__(self, backtesting_config,
self.futures_contract_type = trading_enums.FutureContractType.LINEAR_PERPETUAL
self.enable_storage = enable_storage
self.run_on_all_available_time_frames = run_on_all_available_time_frames
self._has_started = False

async def initialize_and_run(self):
if not constants.ENABLE_BACKTESTING:
raise errors.DisabledError("Backtesting is disabled")
self.logger.info(f"Starting on {self.backtesting_files} with {self.symbols_to_create_exchange_classes}")
self.start_time = time.time()
await commons_databases.init_bot_storage(
Expand All @@ -100,11 +106,13 @@ async def initialize_and_run(self):
await self._init_evaluators()
await self._init_service_feeds()
await self._init_exchanges()
self._ensure_limits()
await self._create_evaluators()
await self._create_service_feeds()
await backtesting_api.start_backtesting(self.backtesting)
if logger.BOT_CHANNEL_LOGGER is not None and self.enable_logs:
await self.start_loggers()
self._has_started = True

async def stop_importers(self):
if self.backtesting is not None:
Expand All @@ -125,7 +133,7 @@ async def stop(self, memory_check=False, should_raise=False):
self.logger.warning("No backtesting to stop, there was probably an issue when starting the backtesting")
else:
exchange_managers = trading_api.get_exchange_managers_from_exchange_ids(self.exchange_manager_ids)
if exchange_managers and self.enable_storage:
if exchange_managers and self.enable_storage and self._has_started:
try:
for exchange_manager in exchange_managers:
await trading_api.store_history_in_run_storage(exchange_manager)
Expand Down Expand Up @@ -267,6 +275,18 @@ async def _init_service_feeds(self):
self.service_feeds = [service_feed_factory.create_service_feed(feed)
for feed in service_feed_factory.get_available_service_feeds(True)]

def _ensure_limits(self):
for exchange_id in self.exchange_manager_ids:
exchange_configuration = trading_api.get_exchange_configuration_from_exchange_id(exchange_id)
time_frames = exchange_configuration.available_required_time_frames
symbols = exchange_configuration.symbols
start_time, end_time = trading_api.get_exchange_backtesting_time_window(
trading_api.get_exchange_manager_from_exchange_id(exchange_id)
)
limits.ensure_backtesting_limits(
self.symbols_to_create_exchange_classes.keys(), symbols, time_frames, start_time, end_time
)

async def _create_evaluators(self):
for exchange_id in self.exchange_manager_ids:
exchange_configuration = trading_api.get_exchange_configuration_from_exchange_id(exchange_id)
Expand Down
4 changes: 3 additions & 1 deletion octobot/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,9 @@ def _disable_interface_from_param(interface_identifier, param_value, logger):

def _log_environment(logger):
try:
logger.debug(f"Running on {os_util.get_current_platform()} with {os_util.get_octobot_type()}")
bot_type = "cloud" if constants.IS_CLOUD_ENV else "self-hosted"
logger.debug(f"Running {bot_type} OctoBot on {os_util.get_current_platform()} "
f"with {os_util.get_octobot_type()}")
except Exception as e:
logger.error(f"Impossible to identify the current running environment: {e}")

Expand Down
6 changes: 6 additions & 0 deletions octobot/community/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@
from octobot.community.errors import (
RequestError,
StatusCodeRequestError,
BotError,
BotNotFoundError,
NoBotDeviceError,
)
from octobot.community import identifiers_provider
from octobot.community.identifiers_provider import (
Expand Down Expand Up @@ -92,6 +95,9 @@
__all__ = [
"RequestError",
"StatusCodeRequestError",
"BotError",
"BotNotFoundError",
"NoBotDeviceError",
"IdentifiersProvider",
"CommunityUserAccount",
"CommunityFields",
Expand Down
15 changes: 9 additions & 6 deletions octobot/community/authentication.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ def __init__(self, feed_url, config=None):
self._community_feed = None
self._login_completed = None
self._update_bot_lock = None
self._startup_info = None

self._update_sessions_headers()

Expand Down Expand Up @@ -437,13 +438,15 @@ async def load_user_bots(self):
)

async def get_startup_info(self):
if self.user_account.gql_bot_id is None:
raise errors.BotError("No selected bot")
return startup_info.StartupInfo.from_dict(
await self._fetch_startup_info(
self.user_account.gql_bot_id
if self._startup_info is None:
if self.user_account.gql_bot_id is None:
raise errors.BotError("No selected bot")
self._startup_info = startup_info.StartupInfo.from_dict(
await self._fetch_startup_info(
self.user_account.gql_bot_id
)
)
)
return self._startup_info

async def get_subscribed_profile_urls(self):
subscribed_profiles = await self._fetch_subscribed_profiles()
Expand Down
5 changes: 5 additions & 0 deletions octobot/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,11 @@
UNLIMITED_ALLOWED = -1
MAX_ALLOWED_EXCHANGES = int(os.getenv("MAX_ALLOWED_EXCHANGES", str(UNLIMITED_ALLOWED)))
MAX_ALLOWED_SYMBOLS = int(os.getenv("MAX_ALLOWED_SYMBOLS", str(UNLIMITED_ALLOWED)))
MAX_ALLOWED_TIME_FRAMES = int(os.getenv("MAX_ALLOWED_TIME_FRAMES", str(UNLIMITED_ALLOWED)))
MAX_ALLOWED_BACKTESTING_CANDLES_HISTORY = int(os.getenv("MAX_ALLOWED_BACKTESTING_CANDLES_HISTORY",
str(UNLIMITED_ALLOWED)))
ENABLE_AUTOMATIONS = os_util.parse_boolean_environment_var("ENABLE_AUTOMATIONS", "True")
ENABLE_BACKTESTING = os_util.parse_boolean_environment_var("ENABLE_BACKTESTING", "True")

# tentacles
ENV_TENTACLES_URL = "TENTACLES_URL"
Expand Down
18 changes: 18 additions & 0 deletions octobot/errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# This file is part of OctoBot (https://github.com/Drakkar-Software/OctoBot)
# Copyright (c) 2023 Drakkar-Software, All rights reserved.
#
# OctoBot is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either
# version 3.0 of the License, or (at your option) any later version.
#
# OctoBot is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# General Public License for more details.
#
# You should have received a copy of the GNU General Public
# License along with OctoBot. If not, see <https://www.gnu.org/licenses/>.

class DisabledError(Exception):
pass
Loading

0 comments on commit 4c968f9

Please sign in to comment.