Skip to content

Commit 2cf5733

Browse files
author
coding-kitties
authored
Merge pull request #42 from coding-kitties/develop
Develop
2 parents ac745eb + aac16cd commit 2cf5733

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1283
-445
lines changed

LICENSE

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Business Source License 1.1
33
Parameters
44

55
Licensor: coding kitties.
6-
Licensed Work: Investing Algorithm Framework
6+
Licensed Work: Investing Algorithm Framework.
77
The Licensed Work is (c) 2020 coding kitties.
88
Additional Use Grant: You may make use of the Licensed Work, provided that you do
99
not use the Licensed Work for an Algorithm
@@ -14,7 +14,23 @@ Additional Use Grant: You may make use of the Licensed Work, provided that you d
1414
contractors) to sell and host applications created with the Licensed
1515
Work.
1616

17-
Change Date: 2023-06-20
17+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
18+
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
19+
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
21+
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
22+
THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
23+
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
24+
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25+
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
26+
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
28+
IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
30+
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31+
POSSIBILITY OF SUCH DAMAGE.
32+
33+
Change Date: 2023-07-16
1834

1935
Change License: Apache License, Version 2.0
2036

investing_algorithm_framework/__init__.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,3 @@
33
VERSION = (0, 1, 1, 'alpha', 0)
44

55
__all__ = ['get_version']
6-

investing_algorithm_framework/configuration/__init__.py

Lines changed: 20 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -2,70 +2,18 @@
22
import logging.config
33
from typing import Any
44
from importlib import import_module
5-
from enum import Enum
65

76
from investing_algorithm_framework.core.exceptions \
87
import ImproperlyConfigured, OperationalException
98
from investing_algorithm_framework.configuration.config_constants \
10-
import SETTINGS_MODULE_PATH_ENV_NAME, \
11-
SETTINGS_STRATEGY_REGISTERED_APPS, SETTINGS_LOGGING_CONFIG, \
12-
SETTINGS_DATA_PROVIDER_REGISTERED_APPS
9+
import SETTINGS_MODULE_PATH_ENV_NAME, SETTINGS_LOGGING_CONFIG
1310

1411

15-
class TimeUnit(Enum):
16-
SECOND = 'SEC',
17-
MINUTE = 'MIN',
18-
HOUR = 'HR',
19-
ALWAYS = 'ALWAYS'
20-
21-
# Static factory method to convert a string to time_unit
22-
@staticmethod
23-
def from_string(value: str):
24-
25-
if isinstance(value, str):
26-
27-
if value.lower() in ('sec', 'second', 'seconds'):
28-
return TimeUnit.SECOND
29-
30-
elif value.lower() in ('min', 'minute', 'minutes'):
31-
return TimeUnit.MINUTE
32-
33-
elif value.lower() in ('hr', 'hour', 'hours'):
34-
return TimeUnit.HOUR
35-
36-
elif value.lower() in (
37-
'always', 'every', 'continuous', 'every_time'
38-
):
39-
return TimeUnit.ALWAYS
40-
else:
41-
raise OperationalException(
42-
'Could not convert value {} to a time_unit'.format(value)
43-
)
44-
45-
else:
46-
raise OperationalException(
47-
"Could not convert non string value to a time_unit"
48-
)
49-
50-
def equals(self, other):
51-
52-
if isinstance(other, Enum):
53-
return self.value == other.value
54-
else:
55-
56-
try:
57-
time_unit = TimeUnit.from_string(other)
58-
return time_unit == self
59-
except OperationalException:
60-
pass
61-
62-
return other == self.value
63-
64-
65-
class BaseSettings:
12+
class ContextConfiguration:
6613
"""
67-
Base wrapper for settings module. It will load all the default settings
68-
for a given settings module
14+
Base wrapper for ContextConfiguration module. It will load all the
15+
default settings for a given settings module and will allow for run time
16+
specification
6917
"""
7018

7119
def __init__(self) -> None:
@@ -88,29 +36,20 @@ def configure(self, settings_module: str = None) -> None:
8836
# Load the settings module
8937
module = import_module(self.settings_module)
9038

91-
# Base components
92-
tuple_settings = (
93-
SETTINGS_STRATEGY_REGISTERED_APPS,
94-
SETTINGS_DATA_PROVIDER_REGISTERED_APPS,
95-
)
96-
9739
# Set all the attributes of the settings wrapper
9840
for setting in dir(module):
9941

10042
if setting.isupper():
10143
setting_value = getattr(module, setting)
102-
103-
if setting in tuple_settings and \
104-
not isinstance(setting_value, (list, tuple)):
105-
raise ImproperlyConfigured(
106-
"The {} setting must be a list or a "
107-
"tuple.".format(setting))
108-
10944
setattr(self, setting, setting_value)
11045

11146
self._configured = True
11247

113-
logging.config.dictConfig(self[SETTINGS_LOGGING_CONFIG])
48+
try:
49+
logging.config.dictConfig(self[SETTINGS_LOGGING_CONFIG])
50+
except Exception:
51+
# We ignore the error no logging configuration.
52+
pass
11453

11554
@property
11655
def settings_module(self) -> str:
@@ -130,14 +69,14 @@ def __getitem__(self, item) -> Any:
13069

13170
if not hasattr(self, item):
13271
raise OperationalException(
133-
"Setting object doesn't have the specific "
72+
"ContextConfig object doesn't have the specific "
13473
"attribute {}".format(item)
13574
)
13675

13776
return self.__getattribute__(item)
13877
else:
13978
raise OperationalException(
140-
"Settings attributes can only be referenced by string"
79+
"ContextConfig attributes can only be referenced by string"
14180
)
14281

14382
def get(self, key: str, default: Any = None) -> Any:
@@ -153,5 +92,12 @@ def get(self, key: str, default: Any = None) -> Any:
15392

15493
return default
15594

95+
def set(self, key: str, value: Any) -> None:
96+
97+
if hasattr(self, key):
98+
raise OperationalException(
99+
"ContextConfig object already have the specific "
100+
"attribute {} specified".format(key)
101+
)
156102

157-
settings = BaseSettings()
103+
setattr(self, key, value)
Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
# Naming conventions
2-
FRAMEWORK_NAME = 'investing investing_algorithm_framework framework'
2+
FRAMEWORK_NAME = 'investing_algorithm_framework'
33
FRAMEWORK_CORE_MODULE_NAME = 'investing_algorithm_framework.core'
4-
5-
# Setting related constants
6-
SETTINGS_ALGORITHM_PROJECT_NAME = 'ALGORITHM_PROJECT_NAME'
74
SETTINGS_MODULE_PATH_ENV_NAME = 'INVESTING_ALGORITHM_FRAMEWORK_SETTINGS_MODULE'
8-
SETTINGS_DATA_PROVIDER_REGISTERED_APPS = 'INSTALLED_DATA_PROVIDER_APPS'
9-
SETTINGS_STRATEGY_REGISTERED_APPS = 'INSTALLED_STRATEGY_APPS'
10-
SETTINGS_MAX_WORKERS = 'DEFAULT_MAX_WORKERS'
5+
6+
# Project related constants
7+
BASE_DIR = 'BASE_DIR'
8+
SETTINGS_PROJECT_NAME = 'PROJECT_NAME'
9+
SETTINGS_MAX_CONCURRENT_WORKERS = 'MAX_CONCURRENT_WORKERS'
1110
SETTINGS_CONTEXT_CONFIGURATION = 'CONTEXT_CONFIGURATION'
1211
SETTINGS_LOGGING_CONFIG = 'LOGGING'
1312

14-
# Operational constants
15-
DEFAULT_MAX_WORKERS = 2
16-
1713
# Database related constants
18-
BASE_DIR = 'BASE_DIR'
14+
DATABASE_CONFIG = 'DATABASE_CONFIG'
1915
DATABASE_NAME = 'DATABASE_NAME'
16+
DATABASE_TYPE = 'DATABASE_TYPE'
17+
DATABASE_DIRECTORY_PATH = 'DATABASE_DIRECTORY_PATH'
18+
DATABASE_URL = 'DATABASE_URL'
19+
20+
DEFAULT_MAX_WORKERS = 2

investing_algorithm_framework/configuration/setup/default_template_creators.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,18 @@ def create(self) -> None:
9191

9292
# Format placeholders in file if needed
9393
if filename in [
94+
'Dockerfile-template',
95+
'requirements.txt-template',
9496
'manage.py-template',
9597
'settings.py-template',
96-
'context.py-template'
98+
'context.py-template',
99+
'extensions.py-template',
100+
'data_providers.py-template',
101+
'strategies.py-template',
102+
'order_executors.py-template'
97103
]:
98-
99104
# Read the file
100105
with open(destination_path, 'r') as file:
101-
102106
file_data = file.read()
103107

104108
# Replace the placeholder with the

investing_algorithm_framework/configuration/setup/template_creator.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ class TemplateCreator(Template, ABC):
1010
rewrite_template_suffixes = (
1111
# Allow shipping invalid .py files without byte-compilation.
1212
('.py-template', '.py'),
13+
('-template', '')
1314
)
1415

1516
def __init__(self, bot_project_directory: str, bot_name: str) -> None:

investing_algorithm_framework/core/context/context.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1+
import logging
12
from typing import Type
23

3-
from investing_algorithm_framework.configuration import settings
4+
from investing_algorithm_framework.configuration import ContextConfiguration
5+
from investing_algorithm_framework.configuration.config_constants import \
6+
FRAMEWORK_NAME
47
from investing_algorithm_framework.core.exceptions import OperationalException
58
from investing_algorithm_framework.core.utils import Singleton
69
from investing_algorithm_framework.core.state import State
710

11+
logger = logging.getLogger(FRAMEWORK_NAME)
12+
813

914
class Context(metaclass=Singleton):
1015
"""
@@ -17,16 +22,16 @@ class Context(metaclass=Singleton):
1722
_state: State = None
1823

1924
# Settings reference
20-
settings = settings
25+
_config = ContextConfiguration()
2126

2227
def register_initial_state(self, state: Type[State]) -> None:
2328
self._state = state(context=self)
2429

25-
def transition_to(self, bot_state: Type[State]) -> None:
30+
def transition_to(self, state: Type[State]) -> None:
2631
"""
2732
Function to change the running BotState at runtime.
2833
"""
29-
self._state = bot_state(context=self)
34+
self._state = state(context=self)
3035

3136
def _check_state(self, raise_exception: bool = False) -> bool:
3237
"""
@@ -61,3 +66,7 @@ def _run_state(self) -> None:
6166
self._state.start()
6267
transition_state = self._state.get_transition_state_class()
6368
self.transition_to(transition_state)
69+
70+
@property
71+
def config(self) -> ContextConfiguration:
72+
return self._config

investing_algorithm_framework/core/exceptions.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,3 @@ class OperationalException(Exception):
1414
"""
1515
def __init__(self, message) -> None:
1616
super(OperationalException, self).__init__(message)
17-
18-
19-
class DatabaseOperationalException(Exception):
20-
"""
21-
Class DatabaseOperationalException: Exception class indicating a problem
22-
occurred during usage of the database
23-
"""
24-
def __init__(self, message) -> None:
25-
super(DatabaseOperationalException, self).__init__(message)

investing_algorithm_framework/core/extensions.py

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
1-
from investing_algorithm_framework.core.resolvers.database_resolver \
2-
import DatabaseResolver
31
from investing_algorithm_framework.core.resolvers.class_resolver \
42
import ClassResolver
53

6-
__all__ = ['DatabaseResolver', 'ClassResolver']
4+
__all__ = ['ClassResolver']

0 commit comments

Comments
 (0)