Skip to content

Commit

Permalink
Remove support for duplicates and a lil bit of clean up. (#151)
Browse files Browse the repository at this point in the history
* a lil bit of cleanup

* bugfix

* v bump
  • Loading branch information
ZENALC authored Dec 26, 2021
1 parent 13cc112 commit c0d274b
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 34 deletions.
19 changes: 3 additions & 16 deletions algobot/interface/builder/strategy_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Strategy manager.
"""
import os
from typing import TYPE_CHECKING, Dict
from typing import TYPE_CHECKING

from PyQt5.QtWidgets import QComboBox, QDialog, QLabel, QPushButton, QSizePolicy, QSpacerItem, QVBoxLayout

Expand All @@ -24,7 +24,7 @@ def __init__(self, parent: 'Interface'):
self.configuration = self.parent.configuration
self.layout = QVBoxLayout()

self.json_strategies = self.parse_strategies()
self.json_strategies = self.configuration.json_strategies
self.strategies_found_label = QLabel(f"{len(self.json_strategies)} strategies available for management.")
self.strategies_found_label.setFont(get_bold_font())
self.layout.addWidget(self.strategies_found_label)
Expand Down Expand Up @@ -55,25 +55,12 @@ def control_state(self):
self.strategies_combobox.setEnabled(enable)
self.delete_button.setEnabled(enable)

def parse_strategies(self) -> Dict[str, dict]:
"""
Parse strategies in a way that the strategy name is the key and the strategy along with the path is the value.
:return: New parsed dictionary.
"""
new_dict = {}
for path, strategy in self.configuration.json_strategies_with_path:
strategy_name = strategy['name']
new_dict[strategy_name] = strategy
new_dict[strategy_name]['path'] = path

return new_dict

def reset_gui(self):
"""
Reset GUI by refreshing dictionary information.
"""
self.configuration.reload_custom_strategies()
self.json_strategies = self.parse_strategies()
self.json_strategies = self.configuration.json_strategies
self.strategies_found_label.setText(f"{len(self.json_strategies)} strategies available for management.")
self.strategies_combobox.clear()
self.strategies_combobox.addItems(self.json_strategies.keys())
Expand Down
2 changes: 1 addition & 1 deletion algobot/interface/config_utils/slot_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ def load_custom_strategy_slots(config_obj: Configuration):
:return: None
"""
# pylint: disable=too-many-locals
for strategy in config_obj.json_strategies:
for strategy in config_obj.json_strategies.values():

strategy_description = strategy.get('description', "Custom Strategy")
strategy_name = strategy['name']
Expand Down
2 changes: 1 addition & 1 deletion algobot/interface/config_utils/strategy_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def get_strategies(config_obj: Configuration, caller: str) -> List[Dict[str, Any
:return: List of strategy information.
"""
strategies = []
for custom_strategy in config_obj.json_strategies:
for custom_strategy in config_obj.json_strategies.values():
strategy_name = custom_strategy['name']
if strategy_enabled(config_obj, strategy_name, caller):
strategies.append(config_obj.strategy_dict[config_obj.get_category_tab(caller), strategy_name])
Expand Down
11 changes: 4 additions & 7 deletions algobot/interface/configuration.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,9 +104,8 @@ def __init__(self, parent: Interface, logger: Logger = None):
self.optimizerConfigurationTabWidget
]

self.json_strategies_with_path = get_json_strategies()
self.json_strategies = [strategy_item[1] for strategy_item in self.json_strategies_with_path]
self.custom_strategies = [strategy['name'] for strategy in self.json_strategies]
self.json_strategies = get_json_strategies(self.parent.add_to_live_activity_monitor)
self.custom_strategies = list(self.json_strategies.keys())
self.strategies = {}

# Hidden strategies dynamically populated.
Expand All @@ -123,10 +122,8 @@ def reload_custom_strategies(self):
"""
Reload custom strategies after creating a strategy.
"""
self.json_strategies_with_path = get_json_strategies()
self.json_strategies = [strategy_item[1] for strategy_item in self.json_strategies_with_path]
self.custom_strategies = [strategy['name'] for strategy in self.json_strategies]

self.json_strategies = get_json_strategies(self.parent.add_to_live_activity_monitor)
self.custom_strategies = list(self.json_strategies.keys())
self.hidden_strategies = set(self.custom_strategies)

clear_layout(self.hideStrategiesFormLayout)
Expand Down
37 changes: 32 additions & 5 deletions algobot/strategies/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"""
import json
import os
from typing import List, Tuple
from typing import Callable, Dict, Optional

from talib import abstract

Expand Down Expand Up @@ -61,10 +61,10 @@ def parse_custom_strategy_json(json_file: str) -> dict:
return loaded_dict


def get_json_strategies() -> List[Tuple[str, dict]]:
def get_json_strategies(callback: Optional[Callable] = None) -> Dict[str, dict]:
"""
Get JSON strategies.
:return: List of tuple containing JSON path and then JSON strategies.
:return: Dictionary of strategies.
"""
# Just in case if the directory doesn't already exist.
os.makedirs(STRATEGIES_DIR, exist_ok=True)
Expand All @@ -73,9 +73,36 @@ def get_json_strategies() -> List[Tuple[str, dict]]:
strategy_files = [os.path.join(STRATEGIES_DIR, file_name) for file_name in os.listdir(STRATEGIES_DIR)
if file_name.lower().endswith('.json')]

return [(json_file, parse_custom_strategy_json(json_file)) for json_file in strategy_files]
# We must ensure that there aren't any strategies with the same name.
strategies = {}
duplicates = set()

for json_file in strategy_files:
parsed_json = parse_custom_strategy_json(json_file)
parsed_json['path'] = json_file

strategy_name = parsed_json['name']

if strategy_name in duplicates:
continue

if strategy_name in strategies:
duplicates.add(strategy_name)
strategies.pop(strategy_name)
continue

strategies[strategy_name] = parsed_json

if len(duplicates) > 0:
if callback is not None:
callback(f"Found duplicate strategies: {duplicates}. Algobot will ignore them. If you want to use them "
f"anyway, rename them.")
else:
print(f"Found duplicate strategies: {duplicates}. Ignoring them.")

return strategies


if __name__ == '__main__':
import pprint
pprint.pprint(get_json_strategies()[0][1])
pprint.pprint(get_json_strategies())
8 changes: 5 additions & 3 deletions algobot/traders/backtester.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,9 +408,11 @@ def get_all_permutations(self, combos: dict) -> List[dict]:

for strategy_name, strategy_items in strategies.items():
for trend, trend_items in strategy_items.items():
if trend == 'name': # Must cast to list here, or product will be of string characters.
strategy_items[trend] = [trend_items]
continue # This is not needed.
if not isinstance(trend_items, dict): # Must cast to list here, or product will be of characters.
if not isinstance(trend_items, list):
strategy_items[trend] = [trend_items]

continue # This is not needed as it's not a trend.

for uuid, uuid_items in trend_items.items():
for indicator, indicator_value in uuid_items.items():
Expand Down
2 changes: 1 addition & 1 deletion version.txt
Original file line number Diff line number Diff line change
@@ -1 +1 @@
2.1.0
2.1.1

0 comments on commit c0d274b

Please sign in to comment.