Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 0 additions & 8 deletions docs/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,6 @@ pytest tests/test_<file_name>.py::test_<method_name>
flake8 investing_algorithm_framework
```

### 3. Test if all type-hints are correct

#### Run mypy

``` bash
mypy investing_algorithm_framework
```

### Process: Your own code changes

All code changes, regardless of who does them, need to be reviewed and merged by someone else.
Expand Down
1 change: 1 addition & 0 deletions investing_algorithm_framework/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@

VERSION = (0, 1, 0, 'alpha', 0)

__all__ = ['get_version']
6 changes: 4 additions & 2 deletions investing_algorithm_framework/__main__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
"""
Invokes investing_algorithm_framework-admin when the investing_algorithm_framework framework module is run as a script.
Example: python -m investing_algorithm_framework create_standard_algo SampleAlgorithm
Invokes investing_algorithm_framework-admin when the
investing_algorithm_framework framework module is run as a script.
Example:
python -m investing_algorithm_framework create_standard_algo SampleAlgorithm
"""

from investing_algorithm_framework.management import execute_from_command_line
Expand Down
44 changes: 32 additions & 12 deletions investing_algorithm_framework/configuration/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@
from importlib import import_module
from enum import Enum

from investing_algorithm_framework.core.exceptions import ImproperlyConfigured, OperationalException
from investing_algorithm_framework.configuration.config_constants import SETTINGS_MODULE_PATH_ENV_NAME, \
SETTINGS_STRATEGY_REGISTERED_APPS, SETTINGS_DATA_PROVIDER_REGISTERED_APPS, SETTINGS_LOGGING_CONFIG
from investing_algorithm_framework.core.exceptions \
import ImproperlyConfigured, OperationalException
from investing_algorithm_framework.configuration.config_constants \
import SETTINGS_MODULE_PATH_ENV_NAME, \
SETTINGS_STRATEGY_REGISTERED_APPS, SETTINGS_LOGGING_CONFIG, \
SETTINGS_DATA_PROVIDER_REGISTERED_APPS


class TimeUnit(Enum):
Expand All @@ -30,13 +33,19 @@ def from_string(value: str):
elif value.lower() in ('hr', 'hour', 'hours'):
return TimeUnit.HOUR

elif value.lower() in ('always', 'every', 'continuous', 'every_time'):
elif value.lower() in (
'always', 'every', 'continuous', 'every_time'
):
return TimeUnit.ALWAYS
else:
raise OperationalException('Could not convert value {} to a time_unit'.format(value))
raise OperationalException(
'Could not convert value {} to a time_unit'.format(value)
)

else:
raise OperationalException("Could not convert non string value to a time_unit")
raise OperationalException(
"Could not convert non string value to a time_unit"
)

def equals(self, other):

Expand All @@ -55,7 +64,8 @@ def equals(self, other):

class BaseSettings:
"""
Base wrapper for settings module. It will load all the default settings for a given settings module
Base wrapper for settings module. It will load all the default settings
for a given settings module
"""

def __init__(self) -> None:
Expand All @@ -66,7 +76,9 @@ def configure(self, settings_module: str = None) -> None:
self._settings_module = settings_module

if settings_module is None:
self.settings_module = os.environ.get(SETTINGS_MODULE_PATH_ENV_NAME)
self.settings_module = os.environ.get(
SETTINGS_MODULE_PATH_ENV_NAME
)
else:
self.settings_module = settings_module

Expand All @@ -88,8 +100,11 @@ def configure(self, settings_module: str = None) -> None:
if setting.isupper():
setting_value = getattr(module, setting)

if setting in tuple_settings and not isinstance(setting_value, (list, tuple)):
raise ImproperlyConfigured("The %s setting must be a list or a tuple. " % setting)
if setting in tuple_settings and \
not isinstance(setting_value, (list, tuple)):
raise ImproperlyConfigured(
"The {} setting must be a list or a "
"tuple.".format(setting))

setattr(self, setting, setting_value)

Expand All @@ -114,11 +129,16 @@ def __getitem__(self, item) -> Any:
if isinstance(item, str):

if not hasattr(self, item):
raise OperationalException("Setting object doesn't have the specific attribute {}".format(item))
raise OperationalException(
"Setting object doesn't have the specific "
"attribute {}".format(item)
)

return self.__getattribute__(item)
else:
raise OperationalException("Settings attributes can only be referenced by string")
raise OperationalException(
"Settings attributes can only be referenced by string"
)

def get(self, key: str, default: Any = None) -> Any:
"""
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
from investing_algorithm_framework.configuration.setup.default_template_creators import DefaultProjectCreator
from investing_algorithm_framework.configuration.setup\
.default_template_creators import DefaultProjectCreator

__all__ = ['DefaultProjectCreator']
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

import investing_algorithm_framework
from investing_algorithm_framework.core.exceptions import ImproperlyConfigured
from investing_algorithm_framework.configuration.setup.template_creator import TemplateCreator
from investing_algorithm_framework.configuration.setup.template_creator \
import TemplateCreator


class DefaultProjectCreator(TemplateCreator):
Expand All @@ -15,24 +16,32 @@ def configure(self) -> None:
bot_dir = os.path.join(self._bot_project_directory, self._bot_name)

if os.path.exists(bot_dir):
raise ImproperlyConfigured("Project destination directory {} already exists".format(self._bot_name))
raise ImproperlyConfigured("Project destination directory {} "
"already exists".format(self._bot_name))

def create(self) -> None:

# Find the default template directory
template_dir = os.path.join(investing_algorithm_framework.__path__[0], self.TEMPLATE_ROOT_DIR)
template_dir = os.path.join(
investing_algorithm_framework.__path__[0], self.TEMPLATE_ROOT_DIR
)

for root, dirs, files in os.walk(template_dir):

# Get the last part of the path
# This is used as the basis for the copying
path_rest = root[len(template_dir) + 1:]

# Replace template investing_algorithm_framework directory with given investing_algorithm_framework name
path_rest = path_rest.replace(self.PROJECT_TEMPLATE_DIR_NAME, self._bot_name)
# Replace template investing_algorithm_framework directory with
# given investing_algorithm_framework name
path_rest = path_rest.replace(
self.PROJECT_TEMPLATE_DIR_NAME, self._bot_name
)

# Create the directories if they don't exist
destination_dir = os.path.join(self._bot_project_directory, path_rest)
destination_dir = os.path.join(
self._bot_project_directory, path_rest
)
os.makedirs(destination_dir, exist_ok=True)

for dirname in dirs[:]:
Expand All @@ -54,14 +63,17 @@ def create(self) -> None:
for old_suffix, new_suffix in self.rewrite_template_suffixes:

if destination_path.endswith(old_suffix):
destination_path = destination_path[:-len(old_suffix)] + new_suffix
destination_path = \
destination_path[:-len(old_suffix)] + new_suffix
break # Only rewrite once

if os.path.exists(destination_path):
raise ImproperlyConfigured (
raise ImproperlyConfigured(
"{} already exists. Overlaying {} {} into an existing "
"directory won't replace conflicting "
"files.".format(destination_path, filename, destination_path)
"files.".format(
destination_path, filename, destination_path
)
)

copyfile(template_path, destination_path)
Expand All @@ -72,20 +84,29 @@ def create(self) -> None:
except OSError:
raise ImproperlyConfigured(
"Notice: Couldn't set permission bits on {}. You're "
"probably using an uncommon filesystem setup.".format(destination_path)
"probably using an uncommon filesystem setup.".format(
destination_path
)
)

# Format placeholders in file if needed
if filename in ['manage.py-template', 'settings.py-template', 'context.py-template']:
if filename in [
'manage.py-template',
'settings.py-template',
'context.py-template'
]:

# Read the file
with open(destination_path, 'r') as file:

file_data = file.read()

# Replace the placeholder with the investing_algorithm_framework name
file_data = file_data.replace(self.PROJECT_NAME_PLACEHOLDER, self._bot_name)
# Replace the placeholder with the
# investing_algorithm_framework name
file_data = file_data.replace(
self.PROJECT_NAME_PLACEHOLDER, self._bot_name
)

# Write the file out again
with open(destination_path, 'w') as file:
file.write(file_data)
file.write(file_data)
8 changes: 5 additions & 3 deletions investing_algorithm_framework/configuration/setup/template.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@

class Template:
"""
A template class is responsible for creating a templates for the investing_algorithm_framework.
A template class is responsible for creating a templates for the
investing_algorithm_framework.
"""

def __init__(self, bot_project_directory: str, bot_name: str) -> None:
"""
investing_algorithm_framework project directory is the root directory of the given
investing_algorithm_framework. The algorithm_name will be the same as the root project directory. For
investing_algorithm_framework project directory is the root
directory of the given investing_algorithm_framework. The
algorithm_name will be the same as the root project directory. For
simplicity it is explicitly passed as a parameter
"""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ def __init__(self, bot_project_directory: str, bot_name: str) -> None:
@abstractmethod
def create(self) -> None:
"""
Create here the template, it is recommended to first call the configure method, this will check if
everything is setup correctly.
Create here the template, it is recommended to first call the configure
method, this will check if everything is setup correctly.
"""

pass
Expand All @@ -37,5 +37,3 @@ def make_writeable(filename):
st = os.stat(filename)
new_permissions = stat.S_IMODE(st.st_mode) | stat.S_IWUSR
os.chmod(filename, new_permissions)


2 changes: 2 additions & 0 deletions investing_algorithm_framework/core/context/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
from investing_algorithm_framework.core.context.context import Context

__all__ = ['Context']
11 changes: 6 additions & 5 deletions investing_algorithm_framework/core/context/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@

class Context(metaclass=Singleton):
"""
The Context defines the current state of the running algorithms. It also maintains a reference to an instance of a
state subclass, which represents the current state of the context instance.
The Context defines the current state of the running algorithms. It
also maintains a reference to an instance of a state subclass, which
represents the current state of the context instance.
"""

# A reference to the current state of the context.
Expand All @@ -36,8 +37,9 @@ def _check_state(self, raise_exception: bool = False) -> bool:

if raise_exception:
raise OperationalException(
"Context doesn't have a state. Make sure that you set the state either "
"by initializing it or making sure that you transition to a new valid state."
"Context doesn't have a state. Make sure that you set "
"the state either by initializing it or making sure that "
"you transition to a new valid state."
)
else:
return False
Expand All @@ -59,4 +61,3 @@ def _run_state(self) -> None:
self._state.start()
transition_state = self._state.get_transition_state_class()
self.transition_to(transition_state)

2 changes: 2 additions & 0 deletions investing_algorithm_framework/core/events/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
from investing_algorithm_framework.core.events.observable import Observable
from investing_algorithm_framework.core.events.observer import Observer

__all__ = ['Observable', 'Observer']
9 changes: 6 additions & 3 deletions investing_algorithm_framework/core/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,25 @@
class ImproperlyConfigured(Exception):
"""
Class ImproperlyConfigured: Exception class indicating a problem with the configuration of the investing_algorithm_framework
Class ImproperlyConfigured: Exception class indicating a problem with
the configuration of the investing_algorithm_framework
"""
def __init__(self, message) -> None:
super(ImproperlyConfigured, self).__init__(message)


class OperationalException(Exception):
"""
Class OperationalException: Exception class indicating a problem occurred during running of the investing_algorithm_framework
Class OperationalException: Exception class indicating a problem occurred
during running of the investing_algorithm_framework
"""
def __init__(self, message) -> None:
super(OperationalException, self).__init__(message)


class DatabaseOperationalException(Exception):
"""
Class DatabaseOperationalException: Exception class indicating a problem occurred during usage of the database
Class DatabaseOperationalException: Exception class indicating a problem
occurred during usage of the database
"""
def __init__(self, message) -> None:
super(DatabaseOperationalException, self).__init__(message)
5 changes: 4 additions & 1 deletion investing_algorithm_framework/core/executors/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
from investing_algorithm_framework.core.executors.executor import Executor
from investing_algorithm_framework.core.executors.execution_scheduler import ExecutionScheduler
from investing_algorithm_framework.core.executors.execution_scheduler \
import ExecutionScheduler

__all__ = ['Executor', 'ExecutionScheduler']
Loading