Skip to content

Commit e25275c

Browse files
author
investingbots
authored
Merge pull request #5 from investingbots/feature_base_strategy
Feature base strategy
2 parents 828be0b + ed9453b commit e25275c

Some content is hidden

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

60 files changed

+2516
-410
lines changed

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,9 @@ config.json
129129
bot_configuration.db
130130
*.db
131131
.idea
132-
*log*
132+
*log*
133+
134+
!plugins/strategies/
135+
plugins/strategies/*.py
136+
!plugins/data_providers/
137+
plugins/data_providers/*.py

LICENSE

Lines changed: 674 additions & 21 deletions
Large diffs are not rendered by default.

bot/bot.py

Lines changed: 0 additions & 99 deletions
This file was deleted.

bot/configuration/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
from bot.configuration.configuration import Configuration
22
from bot.configuration.arguments import Arguments
3+

bot/configuration/arguments.py

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,71 +3,79 @@
33
from pathlib import Path
44
from typing import Any, Dict, List, Optional
55

6-
from bot.configuration.cli_options import AVAILABLE_CLI_OPTIONS
6+
from bot import __version__
77
from bot import constants
88
from bot import DependencyException
9+
from bot.configuration.bot_configuration import initialize
910

1011
logger = logging.getLogger(__name__)
1112

1213

13-
ARGS_COMMON = ["version", "config"]
14+
class Argument:
15+
16+
def __init__(self, *args, **kwargs):
17+
self.cli = args
18+
self.kwargs = kwargs
19+
20+
21+
# Declarations of the command line interface commands
22+
CLI_COMMANDS = {
23+
"version": Argument(
24+
'-V', '--version',
25+
action='version',
26+
version=f'%(prog)s {__version__}',
27+
),
28+
"config": Argument(
29+
'-c', '--config',
30+
help="Specify configuration file (default: {}".format(constants.DEFAULT_CONFIG),
31+
action='append',
32+
metavar='PATH',
33+
),
34+
}
1435

1536

1637
class Arguments:
1738
"""
18-
Arguments Class. Manage the arguments received by the cli
39+
Arguments Class. Functions as a utilities class to manage the arguments received by the command line interface,
1940
"""
2041

2142
def __init__(self, args: Optional[List[str]]) -> None:
22-
23-
# Map the args
2443
self.args = args
25-
self._parsed_arg: Optional[argparse.Namespace] = None
44+
self._parsed_args: Optional[argparse.Namespace] = None
45+
self.parser = argparse.ArgumentParser()
2646

27-
def get_parsed_arg(self) -> Dict[str, Any]:
47+
@property
48+
def parsed_args(self) -> Dict[str, Any]:
2849
"""
2950
Return the list of arguments
3051
:return: List[str] List of arguments
3152
"""
3253

33-
if self._parsed_arg is None:
34-
self._build_sub_commands()
35-
self._parsed_arg = self._parse_args()
54+
if self._parsed_args is None:
55+
self.build_args()
56+
self._parsed_args = self._parse_args()
3657

37-
return vars(self._parsed_arg)
58+
return vars(self._parsed_args)
3859

3960
def _parse_args(self) -> argparse.Namespace:
4061
"""
4162
Parses given arguments and returns an argparse Namespace instance.
4263
"""
4364
parsed_arg = self.parser.parse_args(self.args)
4465

45-
# Workaround issue in argparse with action='append' and default value
46-
# (see https://bugs.python.org/issue16399)
47-
# Allow no-config for certain commands (like downloading / plotting)
48-
49-
if 'config' in parsed_arg and parsed_arg.config is None and (Path.cwd() / constants.DEFAULT_CONFIG).is_file():
50-
parsed_arg.config = [constants.DEFAULT_CONFIG]
66+
if 'config' in parsed_arg and parsed_arg.config is None or (Path.cwd() / constants.DEFAULT_CONFIG).is_file():
67+
parsed_arg.config = constants.DEFAULT_CONFIG
5168
else:
5269
raise DependencyException("config.json file is not specified, "
5370
"please see the configuration section in the docs")
5471

5572
return parsed_arg
5673

57-
@staticmethod
58-
def _build_args(option_list, parser):
59-
60-
for val in option_list:
61-
opt = AVAILABLE_CLI_OPTIONS[val]
62-
parser.add_argument(*opt.cli, dest=val, **opt.kwargs)
74+
def build_args(self):
6375

64-
def _build_sub_commands(self) -> None:
65-
"""
66-
Builds and attaches all sub commands.
67-
:return: None
68-
"""
76+
for command in CLI_COMMANDS:
77+
argument = CLI_COMMANDS[command]
78+
self.parser.add_argument(*argument.cli, dest=command, **argument.kwargs)
6979

70-
# Build main command
71-
self.parser = argparse.ArgumentParser(description="Trading bot based on value principles")
72-
self._build_args(option_list=ARGS_COMMON, parser=self.parser)
80+
self.parser.set_defaults(func=initialize)
7381

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import logging
2+
from typing import Dict, Any
3+
4+
from bot.configuration.configuration import Configuration
5+
from bot.context.bot_context import BotContext
6+
from bot.context.setup_state import SetupState
7+
8+
9+
logger = logging.getLogger(__name__)
10+
11+
12+
def initialize(args: Dict[str, Any]) -> int:
13+
logger.info("Initializing bot ...")
14+
15+
# Create the configuration
16+
config = Configuration.create_config(args)
17+
18+
context = BotContext()
19+
context.config = config.config
20+
21+
# Initialize context with SetupState
22+
context.initialize(SetupState)
23+
24+
try:
25+
context.run()
26+
except KeyboardInterrupt:
27+
logger.info('SIGINT received, aborting ...')
28+
29+
return 0
30+

bot/configuration/cli_options.py

Lines changed: 0 additions & 53 deletions
This file was deleted.

bot/configuration/configuration.py

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,51 @@
1+
import os
12
import logging
23

3-
from typing import Any, Dict, List, Optional
4+
from typing import Any, Dict, Optional
45

6+
from bot import OperationalException
57
from bot.configuration.load_config import load_config_file
8+
69
logger = logging.getLogger(__name__)
710

811

912
class Configuration:
1013
"""
11-
Class to read and init the bot configuration
14+
Class to read and initialize the bot configuration
1215
"""
1316

14-
def __init__(self, args: Dict[str, Any]) -> None:
15-
self.args = args
16-
self.config: Optional[Dict[str, Any]] = None
17+
def __init__(self, args: Dict[str, Any], direct=True) -> None:
18+
if direct:
19+
raise OperationalException("Direct creation of Configuration is not allowed")
1720

18-
def get_config(self) -> Dict[str, Any]:
19-
"""
20-
Return the config. Use this method to get the bot config
21-
:return: Dict: Bot config
22-
"""
23-
if self.config is None:
24-
self.config = self.load_config()
21+
self._config: Optional[Dict[str, Any]] = None
2522

26-
return self.config
23+
self._initialize(args)
2724

28-
@staticmethod
29-
def load_from_files(files: List[str]) -> Dict[str, Any]:
25+
def _initialize(self, args):
26+
self._config = load_config_file(args.get('config'))
3027

31-
config = {}
28+
@classmethod
29+
def create_config(cls, args: Dict[str, Any]):
3230

33-
# We expect here a list of config filenames
34-
for path in files:
35-
logger.info(f'Using config: {path} ...')
31+
# Check if all dependencies are met
32+
if not args['config']:
33+
raise OperationalException("Config file is not specified")
3634

37-
# Merge config options, overwriting old values
38-
config = load_config_file(path)
35+
config_file = args['config']
3936

40-
return config
37+
if not os.path.isfile(config_file):
38+
raise OperationalException("Specified config location is not a file")
4139

42-
def load_config(self) -> Dict[str, Any]:
40+
if not config_file.endswith('.json'):
41+
raise OperationalException("Specified config file is not a JSON file")
42+
43+
logger.info("Using configuration file: {}".format(config_file))
44+
return Configuration(args, direct=False)
45+
46+
@property
47+
def config(self) -> Dict[str, Any]:
4348
"""
44-
Extract information for sys.argv and load the bot configuration
45-
:return: Configuration dictionary
49+
Return the config.
4650
"""
47-
# Load all configs
48-
config: Dict[str, Any] = self.load_from_files(self.args.get("config", []))
49-
50-
return config
51+
return self._config

0 commit comments

Comments
 (0)