From a2a75d49696b039fb84c0dd1d5decbcb68538ba6 Mon Sep 17 00:00:00 2001 From: Paul Bouquet Date: Fri, 1 Jun 2018 22:02:26 +0200 Subject: [PATCH 01/15] #198 Create arch --- evaluator/evaluator_final.py | 4 +- evaluator/symbol_evaluator.py | 4 +- .../test_evaluator_order_creator.py | 60 ++++++------- trading/trader/order_creation/Advanced/.keep | 0 trading/trader/order_creation/Default/.keep | 0 trading/trader/order_creation/__init__.py | 0 .../order_creation/abstract_order_creator.py | 84 +++++++++---------- 7 files changed, 76 insertions(+), 76 deletions(-) create mode 100644 trading/trader/order_creation/Advanced/.keep create mode 100644 trading/trader/order_creation/Default/.keep create mode 100644 trading/trader/order_creation/__init__.py rename evaluator/evaluator_order_creator.py => trading/trader/order_creation/abstract_order_creator.py (83%) diff --git a/evaluator/evaluator_final.py b/evaluator/evaluator_final.py index 4db4598dc..3e75bc0fc 100644 --- a/evaluator/evaluator_final.py +++ b/evaluator/evaluator_final.py @@ -2,7 +2,7 @@ from queue import Queue from config.cst import EvaluatorStates, INIT_EVAL_NOTE -from evaluator.evaluator_order_creator import EvaluatorOrderCreator +from trading.trader.order_creation.abstract_order_creator import AbstractOrderCreator from tools.asynchronous_server import AsynchronousServer from tools.notifications import EvaluatorNotification from tools.evaluators_util import check_valid_eval_note @@ -75,7 +75,7 @@ def create_final_state_orders(self, evaluator_notification): def _create_order_if_possible(self, evaluator_notification, trader): if trader.is_enabled(): with trader.get_portfolio() as pf: - if EvaluatorOrderCreator.can_create_order(self.symbol, self.exchange, self.state, pf): + if AbstractOrderCreator.can_create_order(self.symbol, self.exchange, self.state, pf): FinalEvaluator._push_order_notification_if_possible( self.symbol_evaluator.get_evaluator_order_creator().create_new_order( self.final_eval, diff --git a/evaluator/symbol_evaluator.py b/evaluator/symbol_evaluator.py index 88e735186..8e7195a7a 100644 --- a/evaluator/symbol_evaluator.py +++ b/evaluator/symbol_evaluator.py @@ -2,7 +2,7 @@ from evaluator.evaluator_creator import EvaluatorCreator from evaluator.evaluator_final import FinalEvaluator from evaluator.evaluator_matrix import EvaluatorMatrix -from evaluator.evaluator_order_creator import EvaluatorOrderCreator +from trading.trader.order_creation.abstract_order_creator import AbstractOrderCreator class SymbolEvaluator: @@ -20,7 +20,7 @@ def __init__(self, config, symbol, crypto_currency_evaluator): self.strategies_eval_lists = {} self.finalize_enabled_list = {} - self.evaluator_order_creator = EvaluatorOrderCreator() + self.evaluator_order_creator = AbstractOrderCreator() def set_traders(self, trader): self.traders = trader diff --git a/tests/unit_tests/evaluator_tests/test_evaluator_order_creator.py b/tests/unit_tests/evaluator_tests/test_evaluator_order_creator.py index 9402621e1..eaf7dbfee 100644 --- a/tests/unit_tests/evaluator_tests/test_evaluator_order_creator.py +++ b/tests/unit_tests/evaluator_tests/test_evaluator_order_creator.py @@ -1,7 +1,7 @@ import ccxt import copy -from evaluator.evaluator_order_creator import EvaluatorOrderCreator +from trading.trader.order_creation.abstract_order_creator import AbstractOrderCreator from trading.exchanges.exchange_manager import ExchangeManager from config.cst import EvaluatorStates from tests.test_utils.config import load_test_config @@ -43,31 +43,31 @@ def test_can_create_order(): min_trigger_market = "ADA/BNB" # order from neutral state => false - assert not EvaluatorOrderCreator.can_create_order(symbol, exchange, EvaluatorStates.NEUTRAL, portfolio) + assert not AbstractOrderCreator.can_create_order(symbol, exchange, EvaluatorStates.NEUTRAL, portfolio) # sell order using a currency with 0 available - assert not EvaluatorOrderCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.SHORT, portfolio) - assert not EvaluatorOrderCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.VERY_SHORT, portfolio) + assert not AbstractOrderCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.SHORT, portfolio) + assert not AbstractOrderCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.VERY_SHORT, portfolio) # sell order using a currency with < min available - assert not EvaluatorOrderCreator.can_create_order(min_trigger_symbol, exchange, EvaluatorStates.SHORT, portfolio) - assert not EvaluatorOrderCreator.can_create_order(min_trigger_symbol, exchange, EvaluatorStates.VERY_SHORT, portfolio) + assert not AbstractOrderCreator.can_create_order(min_trigger_symbol, exchange, EvaluatorStates.SHORT, portfolio) + assert not AbstractOrderCreator.can_create_order(min_trigger_symbol, exchange, EvaluatorStates.VERY_SHORT, portfolio) # sell order using a currency with > min available - assert EvaluatorOrderCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.SHORT, portfolio) - assert EvaluatorOrderCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.VERY_SHORT, portfolio) + assert AbstractOrderCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.SHORT, portfolio) + assert AbstractOrderCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.VERY_SHORT, portfolio) # buy order using a market with 0 available - assert not EvaluatorOrderCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.LONG, portfolio) - assert not EvaluatorOrderCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.VERY_LONG, portfolio) + assert not AbstractOrderCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.LONG, portfolio) + assert not AbstractOrderCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.VERY_LONG, portfolio) # buy order using a market with < min available - assert not EvaluatorOrderCreator.can_create_order(min_trigger_market, exchange, EvaluatorStates.LONG, portfolio) - assert not EvaluatorOrderCreator.can_create_order(min_trigger_market, exchange, EvaluatorStates.VERY_LONG, portfolio) + assert not AbstractOrderCreator.can_create_order(min_trigger_market, exchange, EvaluatorStates.LONG, portfolio) + assert not AbstractOrderCreator.can_create_order(min_trigger_market, exchange, EvaluatorStates.VERY_LONG, portfolio) # buy order using a market with > min available - assert EvaluatorOrderCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.LONG, portfolio) - assert EvaluatorOrderCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.VERY_LONG, portfolio) + assert AbstractOrderCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.LONG, portfolio) + assert AbstractOrderCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.VERY_LONG, portfolio) def test_can_create_order_unknown_symbols(): @@ -78,21 +78,21 @@ def test_can_create_order_unknown_symbols(): unknown_everything = "VI?/*s?" # buy order with unknown market - assert not EvaluatorOrderCreator.can_create_order(unknown_market, exchange, EvaluatorStates.LONG, portfolio) - assert not EvaluatorOrderCreator.can_create_order(unknown_market, exchange, EvaluatorStates.VERY_LONG, portfolio) - assert EvaluatorOrderCreator.can_create_order(unknown_market, exchange, EvaluatorStates.SHORT, portfolio) - assert EvaluatorOrderCreator.can_create_order(unknown_market, exchange, EvaluatorStates.VERY_SHORT, portfolio) + assert not AbstractOrderCreator.can_create_order(unknown_market, exchange, EvaluatorStates.LONG, portfolio) + assert not AbstractOrderCreator.can_create_order(unknown_market, exchange, EvaluatorStates.VERY_LONG, portfolio) + assert AbstractOrderCreator.can_create_order(unknown_market, exchange, EvaluatorStates.SHORT, portfolio) + assert AbstractOrderCreator.can_create_order(unknown_market, exchange, EvaluatorStates.VERY_SHORT, portfolio) # sell order with unknown symbol - assert not EvaluatorOrderCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.SHORT, portfolio) - assert not EvaluatorOrderCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.VERY_SHORT, portfolio) - assert EvaluatorOrderCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.LONG, portfolio) - assert EvaluatorOrderCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.VERY_LONG, portfolio) + assert not AbstractOrderCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.SHORT, portfolio) + assert not AbstractOrderCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.VERY_SHORT, portfolio) + assert AbstractOrderCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.LONG, portfolio) + assert AbstractOrderCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.VERY_LONG, portfolio) # neutral state with unknown symbol, market and everything - assert not EvaluatorOrderCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.NEUTRAL, portfolio) - assert not EvaluatorOrderCreator.can_create_order(unknown_market, exchange, EvaluatorStates.NEUTRAL, portfolio) - assert not EvaluatorOrderCreator.can_create_order(unknown_everything, exchange, EvaluatorStates.NEUTRAL, portfolio) + assert not AbstractOrderCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.NEUTRAL, portfolio) + assert not AbstractOrderCreator.can_create_order(unknown_market, exchange, EvaluatorStates.NEUTRAL, portfolio) + assert not AbstractOrderCreator.can_create_order(unknown_everything, exchange, EvaluatorStates.NEUTRAL, portfolio) def _check_order_limits(order, market_status): @@ -144,7 +144,7 @@ def _check_linked_order(order, linked_order, order_type, order_price, market_sta def test_valid_create_new_order(): config, exchange, trader, symbol = _get_tools() portfolio = trader.get_portfolio() - order_creator = EvaluatorOrderCreator() + order_creator = AbstractOrderCreator() market_status = exchange.get_market_status(symbol) @@ -263,7 +263,7 @@ def test_valid_create_new_order(): def test_invalid_create_new_order(): config, exchange, trader, symbol = _get_tools() portfolio = trader.get_portfolio() - order_creator = EvaluatorOrderCreator() + order_creator = AbstractOrderCreator() # portfolio: "BTC": 10 "USD": 1000 min_trigger_market = "ADA/BNB" @@ -294,7 +294,7 @@ def test_invalid_create_new_order(): def test_split_create_new_order(): config, exchange, trader, symbol = _get_tools() portfolio = trader.get_portfolio() - order_creator = EvaluatorOrderCreator() + order_creator = AbstractOrderCreator() last_btc_price = 6943.01 market_status = exchange.get_market_status(symbol) @@ -513,7 +513,7 @@ def _check_portfolio(portfolio, initial_portfolio, orders, only_positivity=False def test_create_order_using_a_lot_of_different_inputs_with_portfolio_reset(): config, exchange, trader, symbol = _get_tools() portfolio = trader.get_portfolio() - order_creator = EvaluatorOrderCreator() + order_creator = AbstractOrderCreator() gradient_step = 0.001 nb_orders = 1 market_status = exchange.get_market_status(symbol) @@ -567,7 +567,7 @@ def _fill_orders(orders, trader): def test_create_order_using_a_lot_of_different_inputs_without_portfolio_reset(): config, exchange, trader, symbol = _get_tools() portfolio = trader.get_portfolio() - order_creator = EvaluatorOrderCreator() + order_creator = AbstractOrderCreator() gradient_step = 0.001 nb_orders = "unknown" market_status = exchange.get_market_status(symbol) diff --git a/trading/trader/order_creation/Advanced/.keep b/trading/trader/order_creation/Advanced/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/trading/trader/order_creation/Default/.keep b/trading/trader/order_creation/Default/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/trading/trader/order_creation/__init__.py b/trading/trader/order_creation/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/evaluator/evaluator_order_creator.py b/trading/trader/order_creation/abstract_order_creator.py similarity index 83% rename from evaluator/evaluator_order_creator.py rename to trading/trader/order_creation/abstract_order_creator.py index 37f04d0b4..ae9442554 100644 --- a/evaluator/evaluator_order_creator.py +++ b/trading/trader/order_creation/abstract_order_creator.py @@ -6,7 +6,7 @@ from tools.symbol_util import split_symbol -class EvaluatorOrderCreator: +class AbstractOrderCreator: def __init__(self): self.MAX_SUM_RESULT = 2 @@ -93,9 +93,9 @@ def create_new_order(self, eval_note, symbol, exchange, trader, portfolio, state quantity = self._get_limit_quantity_from_risk(eval_note, trader, current_portfolio) - limit_price = EvaluatorOrderCreator\ + limit_price = AbstractOrderCreator\ ._adapt_price(symbol_market, price * self._get_limit_price_from_risk(eval_note, trader)) - stop_price = EvaluatorOrderCreator \ + stop_price = AbstractOrderCreator \ ._adapt_price(symbol_market, price * self._get_stop_price_from_risk(trader)) for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, limit_price, @@ -125,7 +125,7 @@ def create_new_order(self, eval_note, symbol, exchange, trader, portfolio, state quantity = self._get_limit_quantity_from_risk(eval_note, trader, market_quantity) - limit_price = EvaluatorOrderCreator\ + limit_price = AbstractOrderCreator\ ._adapt_price(symbol_market, price * self._get_limit_price_from_risk(eval_note, trader)) for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, limit_price, @@ -183,15 +183,15 @@ def _get_limit_price_from_risk(self, eval_note, trader): if eval_note > 0: factor = self.SELL_LIMIT_ORDER_MIN_PERCENT + \ ((1 - abs(eval_note) + 1 - trader.get_risk()) * self.LIMIT_ORDER_ATTENUATION) - return EvaluatorOrderCreator._check_factor(self.SELL_LIMIT_ORDER_MIN_PERCENT, - self.SELL_LIMIT_ORDER_MAX_PERCENT, - factor) + return AbstractOrderCreator._check_factor(self.SELL_LIMIT_ORDER_MIN_PERCENT, + self.SELL_LIMIT_ORDER_MAX_PERCENT, + factor) else: factor = self.BUY_LIMIT_ORDER_MAX_PERCENT - \ ((1 - abs(eval_note) + 1 - trader.get_risk()) * self.LIMIT_ORDER_ATTENUATION) - return EvaluatorOrderCreator._check_factor(self.BUY_LIMIT_ORDER_MIN_PERCENT, - self.BUY_LIMIT_ORDER_MAX_PERCENT, - factor) + return AbstractOrderCreator._check_factor(self.BUY_LIMIT_ORDER_MIN_PERCENT, + self.BUY_LIMIT_ORDER_MAX_PERCENT, + factor) """ Starting point : self.STOP_LOSS_ORDER_MAX_PERCENT @@ -201,9 +201,9 @@ def _get_limit_price_from_risk(self, eval_note, trader): def _get_stop_price_from_risk(self, trader): factor = self.STOP_LOSS_ORDER_MAX_PERCENT - (trader.get_risk() * self.STOP_LOSS_ORDER_ATTENUATION) - return EvaluatorOrderCreator._check_factor(self.STOP_LOSS_ORDER_MIN_PERCENT, - self.STOP_LOSS_ORDER_MAX_PERCENT, - factor) + return AbstractOrderCreator._check_factor(self.STOP_LOSS_ORDER_MIN_PERCENT, + self.STOP_LOSS_ORDER_MAX_PERCENT, + factor) """ Starting point : self.QUANTITY_MIN_PERCENT @@ -215,9 +215,9 @@ def _get_stop_price_from_risk(self, trader): def _get_limit_quantity_from_risk(self, eval_note, trader, quantity): factor = self.QUANTITY_MIN_PERCENT + ((abs(eval_note) + trader.get_risk()) * self.QUANTITY_ATTENUATION) - return EvaluatorOrderCreator._check_factor(self.QUANTITY_MIN_PERCENT, - self.QUANTITY_MAX_PERCENT, - factor) * quantity + return AbstractOrderCreator._check_factor(self.QUANTITY_MIN_PERCENT, + self.QUANTITY_MAX_PERCENT, + factor) * quantity """ Starting point : self.QUANTITY_MARKET_MIN_PERCENT @@ -235,9 +235,9 @@ def _get_market_quantity_from_risk(self, eval_note, trader, quantity, buy=False) if buy: factor *= self.QUANTITY_BUY_MARKET_ATTENUATION - return EvaluatorOrderCreator._check_factor(self.QUANTITY_MARKET_MIN_PERCENT, - self.QUANTITY_MARKET_MAX_PERCENT, - factor) * quantity + return AbstractOrderCreator._check_factor(self.QUANTITY_MARKET_MIN_PERCENT, + self.QUANTITY_MARKET_MAX_PERCENT, + factor) * quantity @staticmethod def _trunc_with_n_decimal_digits(value, digits): @@ -259,11 +259,11 @@ def _adapt_order_quantity_because_quantity(limiting_value, max_value, quantity_t after_rest_quantity_to_adapt = quantity_to_adapt if rest_order_quantity > 0: after_rest_quantity_to_adapt -= rest_order_quantity - valid_last_order_quantity = EvaluatorOrderCreator._adapt_quantity(symbol_market, rest_order_quantity) + valid_last_order_quantity = AbstractOrderCreator._adapt_quantity(symbol_market, rest_order_quantity) orders.append((valid_last_order_quantity, price)) other_orders_quantity = (after_rest_quantity_to_adapt + max_value)/(nb_full_orders+1) - valid_other_orders_quantity = EvaluatorOrderCreator._adapt_quantity(symbol_market, other_orders_quantity) + valid_other_orders_quantity = AbstractOrderCreator._adapt_quantity(symbol_market, other_orders_quantity) orders += [(valid_other_orders_quantity, price)]*int(nb_full_orders) return orders @@ -273,26 +273,26 @@ def _adapt_order_quantity_because_price(limiting_value, max_value, price, symbol nb_full_orders = limiting_value // max_value rest_order_cost = limiting_value % max_value if rest_order_cost > 0: - valid_last_order_quantity = EvaluatorOrderCreator._adapt_quantity(symbol_market, rest_order_cost/price) + valid_last_order_quantity = AbstractOrderCreator._adapt_quantity(symbol_market, rest_order_cost / price) orders.append((valid_last_order_quantity, price)) other_orders_quantity = max_value / price - valid_other_orders_quantity = EvaluatorOrderCreator._adapt_quantity(symbol_market, other_orders_quantity) + valid_other_orders_quantity = AbstractOrderCreator._adapt_quantity(symbol_market, other_orders_quantity) orders += [(valid_other_orders_quantity, price)] * int(nb_full_orders) return orders @staticmethod def _adapt_price(symbol_market, price): - maximal_price_digits = EvaluatorOrderCreator._get_value_or_default(symbol_market[Ecmsc.PRECISION.value], - Ecmsc.PRECISION_PRICE.value, - CURRENCY_DEFAULT_MAX_PRICE_DIGITS) - return EvaluatorOrderCreator._trunc_with_n_decimal_digits(price, maximal_price_digits) + maximal_price_digits = AbstractOrderCreator._get_value_or_default(symbol_market[Ecmsc.PRECISION.value], + Ecmsc.PRECISION_PRICE.value, + CURRENCY_DEFAULT_MAX_PRICE_DIGITS) + return AbstractOrderCreator._trunc_with_n_decimal_digits(price, maximal_price_digits) @staticmethod def _adapt_quantity(symbol_market, quantity): - maximal_volume_digits = EvaluatorOrderCreator._get_value_or_default(symbol_market[Ecmsc.PRECISION.value], - Ecmsc.PRECISION_AMOUNT.value, 0) - return EvaluatorOrderCreator._trunc_with_n_decimal_digits(quantity, maximal_volume_digits) + maximal_volume_digits = AbstractOrderCreator._get_value_or_default(symbol_market[Ecmsc.PRECISION.value], + Ecmsc.PRECISION_AMOUNT.value, 0) + return AbstractOrderCreator._trunc_with_n_decimal_digits(quantity, maximal_volume_digits) """ Checks and adapts the quantity and price of the order to ensure it's exchange compliant: @@ -315,16 +315,16 @@ def _check_and_adapt_order_details_if_necessary(quantity, price, symbol_market): limit_cost = symbol_market_limits[Ecmsc.LIMITS_COST.value] limit_price = symbol_market_limits[Ecmsc.LIMITS_PRICE.value] - min_quantity = EvaluatorOrderCreator._get_value_or_default(limit_amount, Ecmsc.LIMITS_AMOUNT_MIN.value) - max_quantity = EvaluatorOrderCreator._get_value_or_default(limit_amount, Ecmsc.LIMITS_AMOUNT_MAX.value) - min_cost = EvaluatorOrderCreator._get_value_or_default(limit_cost, Ecmsc.LIMITS_COST_MIN.value) - max_cost = EvaluatorOrderCreator._get_value_or_default(limit_cost, Ecmsc.LIMITS_COST_MAX.value) - min_price = EvaluatorOrderCreator._get_value_or_default(limit_price, Ecmsc.LIMITS_PRICE_MIN.value) - max_price = EvaluatorOrderCreator._get_value_or_default(limit_price, Ecmsc.LIMITS_PRICE_MAX.value) + min_quantity = AbstractOrderCreator._get_value_or_default(limit_amount, Ecmsc.LIMITS_AMOUNT_MIN.value) + max_quantity = AbstractOrderCreator._get_value_or_default(limit_amount, Ecmsc.LIMITS_AMOUNT_MAX.value) + min_cost = AbstractOrderCreator._get_value_or_default(limit_cost, Ecmsc.LIMITS_COST_MIN.value) + max_cost = AbstractOrderCreator._get_value_or_default(limit_cost, Ecmsc.LIMITS_COST_MAX.value) + min_price = AbstractOrderCreator._get_value_or_default(limit_price, Ecmsc.LIMITS_PRICE_MIN.value) + max_price = AbstractOrderCreator._get_value_or_default(limit_price, Ecmsc.LIMITS_PRICE_MAX.value) # adapt digits if necessary - valid_quantity = EvaluatorOrderCreator._adapt_quantity(symbol_market, quantity) - valid_price = EvaluatorOrderCreator._adapt_price(symbol_market, price) + valid_quantity = AbstractOrderCreator._adapt_quantity(symbol_market, quantity) + valid_price = AbstractOrderCreator._adapt_price(symbol_market, price) total_order_price = valid_quantity * valid_price @@ -339,11 +339,11 @@ def _check_and_adapt_order_details_if_necessary(quantity, price, symbol_market): nb_orders_according_to_cost = total_order_price / max_cost nb_orders_according_to_quantity = valid_quantity / max_quantity if nb_orders_according_to_cost > nb_orders_according_to_quantity: - return EvaluatorOrderCreator._adapt_order_quantity_because_price(total_order_price, max_cost,price, - symbol_market) + return AbstractOrderCreator._adapt_order_quantity_because_price(total_order_price, max_cost, price, + symbol_market) else: - return EvaluatorOrderCreator._adapt_order_quantity_because_quantity(valid_quantity, max_quantity, - quantity, price, symbol_market) + return AbstractOrderCreator._adapt_order_quantity_because_quantity(valid_quantity, max_quantity, + quantity, price, symbol_market) else: # valid order that can be handled wy the exchange From 827a4bb57942e77d408f05eabe2efb60939a624e Mon Sep 17 00:00:00 2001 From: Paul Bouquet Date: Sun, 3 Jun 2018 09:55:50 +0200 Subject: [PATCH 02/15] Update coveralls token --- .coveralls.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.coveralls.yml b/.coveralls.yml index 8426657a6..517a7c45f 100644 --- a/.coveralls.yml +++ b/.coveralls.yml @@ -1,3 +1,3 @@ service_name: travis-pro -repo_token: JQVHIBvfdoD1tVTbKPVz1zWPYF4dfR14i +repo_token: 1cFP5IeydNWl3yFJ9bj7cWegFHbkYdVZe parallel: true # if the CI is running your build in parallel \ No newline at end of file From 71441f629315170762d57615dca08b07c5549ce8 Mon Sep 17 00:00:00 2001 From: Paul Bouquet Date: Sun, 3 Jun 2018 10:02:28 +0200 Subject: [PATCH 03/15] Add default trader modes --- evaluator/evaluator_final.py | 2 +- evaluator/symbol_evaluator.py | 2 +- .../unit_tests/evaluator_tests/test_evaluator_order_creator.py | 2 +- trading/trader/{order_creation => modes/Default}/__init__.py | 0 .../Advanced/.keep => modes/Default/high_frequency_mode.py} | 0 .../Default/.keep => modes/Default/investor_mode.py} | 0 trading/trader/modes/Default/objective_mode.py | 0 trading/trader/modes/Default/opportunity_mode.py | 0 trading/trader/modes/Default/safe_profit_mode.py | 0 trading/trader/modes/__init__.py | 0 .../trader/{order_creation => modes}/abstract_order_creator.py | 0 11 files changed, 3 insertions(+), 3 deletions(-) rename trading/trader/{order_creation => modes/Default}/__init__.py (100%) rename trading/trader/{order_creation/Advanced/.keep => modes/Default/high_frequency_mode.py} (100%) rename trading/trader/{order_creation/Default/.keep => modes/Default/investor_mode.py} (100%) create mode 100644 trading/trader/modes/Default/objective_mode.py create mode 100644 trading/trader/modes/Default/opportunity_mode.py create mode 100644 trading/trader/modes/Default/safe_profit_mode.py create mode 100644 trading/trader/modes/__init__.py rename trading/trader/{order_creation => modes}/abstract_order_creator.py (100%) diff --git a/evaluator/evaluator_final.py b/evaluator/evaluator_final.py index 3e75bc0fc..fe213ee3f 100644 --- a/evaluator/evaluator_final.py +++ b/evaluator/evaluator_final.py @@ -2,7 +2,7 @@ from queue import Queue from config.cst import EvaluatorStates, INIT_EVAL_NOTE -from trading.trader.order_creation.abstract_order_creator import AbstractOrderCreator +from trading.trader.modes.abstract_order_creator import AbstractOrderCreator from tools.asynchronous_server import AsynchronousServer from tools.notifications import EvaluatorNotification from tools.evaluators_util import check_valid_eval_note diff --git a/evaluator/symbol_evaluator.py b/evaluator/symbol_evaluator.py index 8e7195a7a..a531f13ee 100644 --- a/evaluator/symbol_evaluator.py +++ b/evaluator/symbol_evaluator.py @@ -2,7 +2,7 @@ from evaluator.evaluator_creator import EvaluatorCreator from evaluator.evaluator_final import FinalEvaluator from evaluator.evaluator_matrix import EvaluatorMatrix -from trading.trader.order_creation.abstract_order_creator import AbstractOrderCreator +from trading.trader.modes.abstract_order_creator import AbstractOrderCreator class SymbolEvaluator: diff --git a/tests/unit_tests/evaluator_tests/test_evaluator_order_creator.py b/tests/unit_tests/evaluator_tests/test_evaluator_order_creator.py index c9993c502..7803d8429 100644 --- a/tests/unit_tests/evaluator_tests/test_evaluator_order_creator.py +++ b/tests/unit_tests/evaluator_tests/test_evaluator_order_creator.py @@ -1,7 +1,7 @@ import ccxt import copy -from trading.trader.order_creation.abstract_order_creator import AbstractOrderCreator +from trading.trader.modes.abstract_order_creator import AbstractOrderCreator from trading.exchanges.exchange_manager import ExchangeManager from config.cst import EvaluatorStates from tests.test_utils.config import load_test_config diff --git a/trading/trader/order_creation/__init__.py b/trading/trader/modes/Default/__init__.py similarity index 100% rename from trading/trader/order_creation/__init__.py rename to trading/trader/modes/Default/__init__.py diff --git a/trading/trader/order_creation/Advanced/.keep b/trading/trader/modes/Default/high_frequency_mode.py similarity index 100% rename from trading/trader/order_creation/Advanced/.keep rename to trading/trader/modes/Default/high_frequency_mode.py diff --git a/trading/trader/order_creation/Default/.keep b/trading/trader/modes/Default/investor_mode.py similarity index 100% rename from trading/trader/order_creation/Default/.keep rename to trading/trader/modes/Default/investor_mode.py diff --git a/trading/trader/modes/Default/objective_mode.py b/trading/trader/modes/Default/objective_mode.py new file mode 100644 index 000000000..e69de29bb diff --git a/trading/trader/modes/Default/opportunity_mode.py b/trading/trader/modes/Default/opportunity_mode.py new file mode 100644 index 000000000..e69de29bb diff --git a/trading/trader/modes/Default/safe_profit_mode.py b/trading/trader/modes/Default/safe_profit_mode.py new file mode 100644 index 000000000..e69de29bb diff --git a/trading/trader/modes/__init__.py b/trading/trader/modes/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/trading/trader/order_creation/abstract_order_creator.py b/trading/trader/modes/abstract_order_creator.py similarity index 100% rename from trading/trader/order_creation/abstract_order_creator.py rename to trading/trader/modes/abstract_order_creator.py From 31b7daf8b296638e604140d4478e1bd0eada6d41 Mon Sep 17 00:00:00 2001 From: Paul Bouquet Date: Sun, 3 Jun 2018 10:10:59 +0200 Subject: [PATCH 04/15] Updated trading modes architecture --- evaluator/symbol_evaluator.py | 8 +- .../trading_modes_tests/__init__.py | 0 .../test_mode_creator.py} | 60 ++++++------- .../test_mode_decider.py} | 4 +- trading/trader/modes/Default/investor_mode.py | 1 + ...er_creator.py => abstract_mode_creator.py} | 84 +++++++++---------- .../trader/modes/abstract_mode_decider.py | 8 +- trading/trader/modes/abstract_trading_mode.py | 18 ++++ 8 files changed, 101 insertions(+), 82 deletions(-) create mode 100644 tests/unit_tests/trading_modes_tests/__init__.py rename tests/unit_tests/{evaluator_tests/test_evaluator_order_creator.py => trading_modes_tests/test_mode_creator.py} (89%) rename tests/unit_tests/{evaluator_tests/test_evaluator_final.py => trading_modes_tests/test_mode_decider.py} (97%) rename trading/trader/modes/{abstract_order_creator.py => abstract_mode_creator.py} (81%) rename evaluator/evaluator_final.py => trading/trader/modes/abstract_mode_decider.py (94%) create mode 100644 trading/trader/modes/abstract_trading_mode.py diff --git a/evaluator/symbol_evaluator.py b/evaluator/symbol_evaluator.py index a531f13ee..0d52e090a 100644 --- a/evaluator/symbol_evaluator.py +++ b/evaluator/symbol_evaluator.py @@ -1,8 +1,8 @@ from config.cst import EvaluatorMatrixTypes from evaluator.evaluator_creator import EvaluatorCreator -from evaluator.evaluator_final import FinalEvaluator +from trading.trader.modes.abstract_mode_decider import AbstractTradingModeDecider from evaluator.evaluator_matrix import EvaluatorMatrix -from trading.trader.modes.abstract_order_creator import AbstractOrderCreator +from trading.trader.modes.abstract_mode_creator import AbstractTradingModeCreator class SymbolEvaluator: @@ -20,7 +20,7 @@ def __init__(self, config, symbol, crypto_currency_evaluator): self.strategies_eval_lists = {} self.finalize_enabled_list = {} - self.evaluator_order_creator = AbstractOrderCreator() + self.evaluator_order_creator = AbstractTradingModeCreator() def set_traders(self, trader): self.traders = trader @@ -33,7 +33,7 @@ def add_evaluator_thread_manager(self, exchange, symbol, time_frame, evaluator_t self.evaluator_thread_managers[exchange.get_name()][time_frame] = evaluator_thread else: self.evaluator_thread_managers[exchange.get_name()] = {time_frame: evaluator_thread} - self.final_evaluators[exchange.get_name()] = FinalEvaluator(self, exchange, symbol) + self.final_evaluators[exchange.get_name()] = AbstractTradingModeDecider(self, exchange, symbol) self.matrices[exchange.get_name()] = EvaluatorMatrix(self.config) self.strategies_eval_lists[exchange.get_name()] = EvaluatorCreator.create_strategies_eval_list(self.config) self.finalize_enabled_list[exchange.get_name()] = False diff --git a/tests/unit_tests/trading_modes_tests/__init__.py b/tests/unit_tests/trading_modes_tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/unit_tests/evaluator_tests/test_evaluator_order_creator.py b/tests/unit_tests/trading_modes_tests/test_mode_creator.py similarity index 89% rename from tests/unit_tests/evaluator_tests/test_evaluator_order_creator.py rename to tests/unit_tests/trading_modes_tests/test_mode_creator.py index 7803d8429..e278fdf0a 100644 --- a/tests/unit_tests/evaluator_tests/test_evaluator_order_creator.py +++ b/tests/unit_tests/trading_modes_tests/test_mode_creator.py @@ -1,7 +1,7 @@ import ccxt import copy -from trading.trader.modes.abstract_order_creator import AbstractOrderCreator +from trading.trader.modes.abstract_mode_creator import AbstractTradingModeCreator from trading.exchanges.exchange_manager import ExchangeManager from config.cst import EvaluatorStates from tests.test_utils.config import load_test_config @@ -43,31 +43,31 @@ def test_can_create_order(): min_trigger_market = "ADA/BNB" # order from neutral state => false - assert not AbstractOrderCreator.can_create_order(symbol, exchange, EvaluatorStates.NEUTRAL, portfolio) + assert not AbstractTradingModeCreator.can_create_order(symbol, exchange, EvaluatorStates.NEUTRAL, portfolio) # sell order using a currency with 0 available - assert not AbstractOrderCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.SHORT, portfolio) - assert not AbstractOrderCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.VERY_SHORT, portfolio) + assert not AbstractTradingModeCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.SHORT, portfolio) + assert not AbstractTradingModeCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.VERY_SHORT, portfolio) # sell order using a currency with < min available - assert not AbstractOrderCreator.can_create_order(min_trigger_symbol, exchange, EvaluatorStates.SHORT, portfolio) - assert not AbstractOrderCreator.can_create_order(min_trigger_symbol, exchange, EvaluatorStates.VERY_SHORT, portfolio) + assert not AbstractTradingModeCreator.can_create_order(min_trigger_symbol, exchange, EvaluatorStates.SHORT, portfolio) + assert not AbstractTradingModeCreator.can_create_order(min_trigger_symbol, exchange, EvaluatorStates.VERY_SHORT, portfolio) # sell order using a currency with > min available - assert AbstractOrderCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.SHORT, portfolio) - assert AbstractOrderCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.VERY_SHORT, portfolio) + assert AbstractTradingModeCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.SHORT, portfolio) + assert AbstractTradingModeCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.VERY_SHORT, portfolio) # buy order using a market with 0 available - assert not AbstractOrderCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.LONG, portfolio) - assert not AbstractOrderCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.VERY_LONG, portfolio) + assert not AbstractTradingModeCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.LONG, portfolio) + assert not AbstractTradingModeCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.VERY_LONG, portfolio) # buy order using a market with < min available - assert not AbstractOrderCreator.can_create_order(min_trigger_market, exchange, EvaluatorStates.LONG, portfolio) - assert not AbstractOrderCreator.can_create_order(min_trigger_market, exchange, EvaluatorStates.VERY_LONG, portfolio) + assert not AbstractTradingModeCreator.can_create_order(min_trigger_market, exchange, EvaluatorStates.LONG, portfolio) + assert not AbstractTradingModeCreator.can_create_order(min_trigger_market, exchange, EvaluatorStates.VERY_LONG, portfolio) # buy order using a market with > min available - assert AbstractOrderCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.LONG, portfolio) - assert AbstractOrderCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.VERY_LONG, portfolio) + assert AbstractTradingModeCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.LONG, portfolio) + assert AbstractTradingModeCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.VERY_LONG, portfolio) def test_can_create_order_unknown_symbols(): @@ -78,21 +78,21 @@ def test_can_create_order_unknown_symbols(): unknown_everything = "VI?/*s?" # buy order with unknown market - assert not AbstractOrderCreator.can_create_order(unknown_market, exchange, EvaluatorStates.LONG, portfolio) - assert not AbstractOrderCreator.can_create_order(unknown_market, exchange, EvaluatorStates.VERY_LONG, portfolio) - assert AbstractOrderCreator.can_create_order(unknown_market, exchange, EvaluatorStates.SHORT, portfolio) - assert AbstractOrderCreator.can_create_order(unknown_market, exchange, EvaluatorStates.VERY_SHORT, portfolio) + assert not AbstractTradingModeCreator.can_create_order(unknown_market, exchange, EvaluatorStates.LONG, portfolio) + assert not AbstractTradingModeCreator.can_create_order(unknown_market, exchange, EvaluatorStates.VERY_LONG, portfolio) + assert AbstractTradingModeCreator.can_create_order(unknown_market, exchange, EvaluatorStates.SHORT, portfolio) + assert AbstractTradingModeCreator.can_create_order(unknown_market, exchange, EvaluatorStates.VERY_SHORT, portfolio) # sell order with unknown symbol - assert not AbstractOrderCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.SHORT, portfolio) - assert not AbstractOrderCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.VERY_SHORT, portfolio) - assert AbstractOrderCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.LONG, portfolio) - assert AbstractOrderCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.VERY_LONG, portfolio) + assert not AbstractTradingModeCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.SHORT, portfolio) + assert not AbstractTradingModeCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.VERY_SHORT, portfolio) + assert AbstractTradingModeCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.LONG, portfolio) + assert AbstractTradingModeCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.VERY_LONG, portfolio) # neutral state with unknown symbol, market and everything - assert not AbstractOrderCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.NEUTRAL, portfolio) - assert not AbstractOrderCreator.can_create_order(unknown_market, exchange, EvaluatorStates.NEUTRAL, portfolio) - assert not AbstractOrderCreator.can_create_order(unknown_everything, exchange, EvaluatorStates.NEUTRAL, portfolio) + assert not AbstractTradingModeCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.NEUTRAL, portfolio) + assert not AbstractTradingModeCreator.can_create_order(unknown_market, exchange, EvaluatorStates.NEUTRAL, portfolio) + assert not AbstractTradingModeCreator.can_create_order(unknown_everything, exchange, EvaluatorStates.NEUTRAL, portfolio) def _check_order_limits(order, market_status): @@ -144,7 +144,7 @@ def _check_linked_order(order, linked_order, order_type, order_price, market_sta def test_valid_create_new_order(): config, exchange, trader, symbol = _get_tools() portfolio = trader.get_portfolio() - order_creator = AbstractOrderCreator() + order_creator = AbstractTradingModeCreator() market_status = exchange.get_market_status(symbol) @@ -263,7 +263,7 @@ def test_valid_create_new_order(): def test_invalid_create_new_order(): config, exchange, trader, symbol = _get_tools() portfolio = trader.get_portfolio() - order_creator = AbstractOrderCreator() + order_creator = AbstractTradingModeCreator() # portfolio: "BTC": 10 "USD": 1000 min_trigger_market = "ADA/BNB" @@ -294,7 +294,7 @@ def test_invalid_create_new_order(): def test_split_create_new_order(): config, exchange, trader, symbol = _get_tools() portfolio = trader.get_portfolio() - order_creator = AbstractOrderCreator() + order_creator = AbstractTradingModeCreator() last_btc_price = 6943.01 market_status = exchange.get_market_status(symbol) @@ -513,7 +513,7 @@ def _check_portfolio(portfolio, initial_portfolio, orders, only_positivity=False def test_create_order_using_a_lot_of_different_inputs_with_portfolio_reset(): config, exchange, trader, symbol = _get_tools() portfolio = trader.get_portfolio() - order_creator = AbstractOrderCreator() + order_creator = AbstractTradingModeCreator() gradient_step = 0.001 nb_orders = 1 market_status = exchange.get_market_status(symbol) @@ -569,7 +569,7 @@ def _fill_orders(orders, trader): def test_create_order_using_a_lot_of_different_inputs_without_portfolio_reset(): config, exchange, trader, symbol = _get_tools() portfolio = trader.get_portfolio() - order_creator = AbstractOrderCreator() + order_creator = AbstractTradingModeCreator() gradient_step = 0.001 nb_orders = "unknown" market_status = exchange.get_market_status(symbol) diff --git a/tests/unit_tests/evaluator_tests/test_evaluator_final.py b/tests/unit_tests/trading_modes_tests/test_mode_decider.py similarity index 97% rename from tests/unit_tests/evaluator_tests/test_evaluator_final.py rename to tests/unit_tests/trading_modes_tests/test_mode_decider.py index 4c06fde0e..3a11b57dd 100644 --- a/tests/unit_tests/evaluator_tests/test_evaluator_final.py +++ b/tests/unit_tests/trading_modes_tests/test_mode_decider.py @@ -4,7 +4,7 @@ from evaluator.symbol_evaluator import SymbolEvaluator from trading.trader.trader_simulator import TraderSimulator from evaluator.cryptocurrency_evaluator import CryptocurrencyEvaluator -from evaluator.evaluator_final import FinalEvaluator +from trading.trader.modes.abstract_mode_decider import AbstractTradingModeDecider from evaluator.evaluator_creator import EvaluatorCreator from tests.test_utils.config import load_test_config from evaluator.Util.advanced_manager import AdvancedManager @@ -31,7 +31,7 @@ def _get_tools(): symbol_evaluator.set_trader_simulators(exchange_traders) symbol_evaluator.set_traders(exchange_traders2) symbol_evaluator.strategies_eval_lists[exchange_inst.get_name()] = EvaluatorCreator.create_strategies_eval_list(config) - final_evaluator = FinalEvaluator(symbol_evaluator, exchange_inst, symbol) + final_evaluator = AbstractTradingModeDecider(symbol_evaluator, exchange_inst, symbol) trader_inst.portfolio.portfolio["USDT"] = { Portfolio.TOTAL: 2000, Portfolio.AVAILABLE: 2000 diff --git a/trading/trader/modes/Default/investor_mode.py b/trading/trader/modes/Default/investor_mode.py index e69de29bb..9338ca32d 100644 --- a/trading/trader/modes/Default/investor_mode.py +++ b/trading/trader/modes/Default/investor_mode.py @@ -0,0 +1 @@ +class InvestorMode() \ No newline at end of file diff --git a/trading/trader/modes/abstract_order_creator.py b/trading/trader/modes/abstract_mode_creator.py similarity index 81% rename from trading/trader/modes/abstract_order_creator.py rename to trading/trader/modes/abstract_mode_creator.py index ae9442554..3317ef34e 100644 --- a/trading/trader/modes/abstract_order_creator.py +++ b/trading/trader/modes/abstract_mode_creator.py @@ -6,7 +6,7 @@ from tools.symbol_util import split_symbol -class AbstractOrderCreator: +class AbstractTradingModeCreator: def __init__(self): self.MAX_SUM_RESULT = 2 @@ -93,9 +93,9 @@ def create_new_order(self, eval_note, symbol, exchange, trader, portfolio, state quantity = self._get_limit_quantity_from_risk(eval_note, trader, current_portfolio) - limit_price = AbstractOrderCreator\ + limit_price = AbstractTradingModeCreator\ ._adapt_price(symbol_market, price * self._get_limit_price_from_risk(eval_note, trader)) - stop_price = AbstractOrderCreator \ + stop_price = AbstractTradingModeCreator \ ._adapt_price(symbol_market, price * self._get_stop_price_from_risk(trader)) for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, limit_price, @@ -125,7 +125,7 @@ def create_new_order(self, eval_note, symbol, exchange, trader, portfolio, state quantity = self._get_limit_quantity_from_risk(eval_note, trader, market_quantity) - limit_price = AbstractOrderCreator\ + limit_price = AbstractTradingModeCreator\ ._adapt_price(symbol_market, price * self._get_limit_price_from_risk(eval_note, trader)) for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, limit_price, @@ -183,15 +183,15 @@ def _get_limit_price_from_risk(self, eval_note, trader): if eval_note > 0: factor = self.SELL_LIMIT_ORDER_MIN_PERCENT + \ ((1 - abs(eval_note) + 1 - trader.get_risk()) * self.LIMIT_ORDER_ATTENUATION) - return AbstractOrderCreator._check_factor(self.SELL_LIMIT_ORDER_MIN_PERCENT, - self.SELL_LIMIT_ORDER_MAX_PERCENT, - factor) + return AbstractTradingModeCreator._check_factor(self.SELL_LIMIT_ORDER_MIN_PERCENT, + self.SELL_LIMIT_ORDER_MAX_PERCENT, + factor) else: factor = self.BUY_LIMIT_ORDER_MAX_PERCENT - \ ((1 - abs(eval_note) + 1 - trader.get_risk()) * self.LIMIT_ORDER_ATTENUATION) - return AbstractOrderCreator._check_factor(self.BUY_LIMIT_ORDER_MIN_PERCENT, - self.BUY_LIMIT_ORDER_MAX_PERCENT, - factor) + return AbstractTradingModeCreator._check_factor(self.BUY_LIMIT_ORDER_MIN_PERCENT, + self.BUY_LIMIT_ORDER_MAX_PERCENT, + factor) """ Starting point : self.STOP_LOSS_ORDER_MAX_PERCENT @@ -201,9 +201,9 @@ def _get_limit_price_from_risk(self, eval_note, trader): def _get_stop_price_from_risk(self, trader): factor = self.STOP_LOSS_ORDER_MAX_PERCENT - (trader.get_risk() * self.STOP_LOSS_ORDER_ATTENUATION) - return AbstractOrderCreator._check_factor(self.STOP_LOSS_ORDER_MIN_PERCENT, - self.STOP_LOSS_ORDER_MAX_PERCENT, - factor) + return AbstractTradingModeCreator._check_factor(self.STOP_LOSS_ORDER_MIN_PERCENT, + self.STOP_LOSS_ORDER_MAX_PERCENT, + factor) """ Starting point : self.QUANTITY_MIN_PERCENT @@ -215,9 +215,9 @@ def _get_stop_price_from_risk(self, trader): def _get_limit_quantity_from_risk(self, eval_note, trader, quantity): factor = self.QUANTITY_MIN_PERCENT + ((abs(eval_note) + trader.get_risk()) * self.QUANTITY_ATTENUATION) - return AbstractOrderCreator._check_factor(self.QUANTITY_MIN_PERCENT, - self.QUANTITY_MAX_PERCENT, - factor) * quantity + return AbstractTradingModeCreator._check_factor(self.QUANTITY_MIN_PERCENT, + self.QUANTITY_MAX_PERCENT, + factor) * quantity """ Starting point : self.QUANTITY_MARKET_MIN_PERCENT @@ -235,9 +235,9 @@ def _get_market_quantity_from_risk(self, eval_note, trader, quantity, buy=False) if buy: factor *= self.QUANTITY_BUY_MARKET_ATTENUATION - return AbstractOrderCreator._check_factor(self.QUANTITY_MARKET_MIN_PERCENT, - self.QUANTITY_MARKET_MAX_PERCENT, - factor) * quantity + return AbstractTradingModeCreator._check_factor(self.QUANTITY_MARKET_MIN_PERCENT, + self.QUANTITY_MARKET_MAX_PERCENT, + factor) * quantity @staticmethod def _trunc_with_n_decimal_digits(value, digits): @@ -259,11 +259,11 @@ def _adapt_order_quantity_because_quantity(limiting_value, max_value, quantity_t after_rest_quantity_to_adapt = quantity_to_adapt if rest_order_quantity > 0: after_rest_quantity_to_adapt -= rest_order_quantity - valid_last_order_quantity = AbstractOrderCreator._adapt_quantity(symbol_market, rest_order_quantity) + valid_last_order_quantity = AbstractTradingModeCreator._adapt_quantity(symbol_market, rest_order_quantity) orders.append((valid_last_order_quantity, price)) other_orders_quantity = (after_rest_quantity_to_adapt + max_value)/(nb_full_orders+1) - valid_other_orders_quantity = AbstractOrderCreator._adapt_quantity(symbol_market, other_orders_quantity) + valid_other_orders_quantity = AbstractTradingModeCreator._adapt_quantity(symbol_market, other_orders_quantity) orders += [(valid_other_orders_quantity, price)]*int(nb_full_orders) return orders @@ -273,26 +273,26 @@ def _adapt_order_quantity_because_price(limiting_value, max_value, price, symbol nb_full_orders = limiting_value // max_value rest_order_cost = limiting_value % max_value if rest_order_cost > 0: - valid_last_order_quantity = AbstractOrderCreator._adapt_quantity(symbol_market, rest_order_cost / price) + valid_last_order_quantity = AbstractTradingModeCreator._adapt_quantity(symbol_market, rest_order_cost / price) orders.append((valid_last_order_quantity, price)) other_orders_quantity = max_value / price - valid_other_orders_quantity = AbstractOrderCreator._adapt_quantity(symbol_market, other_orders_quantity) + valid_other_orders_quantity = AbstractTradingModeCreator._adapt_quantity(symbol_market, other_orders_quantity) orders += [(valid_other_orders_quantity, price)] * int(nb_full_orders) return orders @staticmethod def _adapt_price(symbol_market, price): - maximal_price_digits = AbstractOrderCreator._get_value_or_default(symbol_market[Ecmsc.PRECISION.value], - Ecmsc.PRECISION_PRICE.value, - CURRENCY_DEFAULT_MAX_PRICE_DIGITS) - return AbstractOrderCreator._trunc_with_n_decimal_digits(price, maximal_price_digits) + maximal_price_digits = AbstractTradingModeCreator._get_value_or_default(symbol_market[Ecmsc.PRECISION.value], + Ecmsc.PRECISION_PRICE.value, + CURRENCY_DEFAULT_MAX_PRICE_DIGITS) + return AbstractTradingModeCreator._trunc_with_n_decimal_digits(price, maximal_price_digits) @staticmethod def _adapt_quantity(symbol_market, quantity): - maximal_volume_digits = AbstractOrderCreator._get_value_or_default(symbol_market[Ecmsc.PRECISION.value], - Ecmsc.PRECISION_AMOUNT.value, 0) - return AbstractOrderCreator._trunc_with_n_decimal_digits(quantity, maximal_volume_digits) + maximal_volume_digits = AbstractTradingModeCreator._get_value_or_default(symbol_market[Ecmsc.PRECISION.value], + Ecmsc.PRECISION_AMOUNT.value, 0) + return AbstractTradingModeCreator._trunc_with_n_decimal_digits(quantity, maximal_volume_digits) """ Checks and adapts the quantity and price of the order to ensure it's exchange compliant: @@ -315,16 +315,16 @@ def _check_and_adapt_order_details_if_necessary(quantity, price, symbol_market): limit_cost = symbol_market_limits[Ecmsc.LIMITS_COST.value] limit_price = symbol_market_limits[Ecmsc.LIMITS_PRICE.value] - min_quantity = AbstractOrderCreator._get_value_or_default(limit_amount, Ecmsc.LIMITS_AMOUNT_MIN.value) - max_quantity = AbstractOrderCreator._get_value_or_default(limit_amount, Ecmsc.LIMITS_AMOUNT_MAX.value) - min_cost = AbstractOrderCreator._get_value_or_default(limit_cost, Ecmsc.LIMITS_COST_MIN.value) - max_cost = AbstractOrderCreator._get_value_or_default(limit_cost, Ecmsc.LIMITS_COST_MAX.value) - min_price = AbstractOrderCreator._get_value_or_default(limit_price, Ecmsc.LIMITS_PRICE_MIN.value) - max_price = AbstractOrderCreator._get_value_or_default(limit_price, Ecmsc.LIMITS_PRICE_MAX.value) + min_quantity = AbstractTradingModeCreator._get_value_or_default(limit_amount, Ecmsc.LIMITS_AMOUNT_MIN.value) + max_quantity = AbstractTradingModeCreator._get_value_or_default(limit_amount, Ecmsc.LIMITS_AMOUNT_MAX.value) + min_cost = AbstractTradingModeCreator._get_value_or_default(limit_cost, Ecmsc.LIMITS_COST_MIN.value) + max_cost = AbstractTradingModeCreator._get_value_or_default(limit_cost, Ecmsc.LIMITS_COST_MAX.value) + min_price = AbstractTradingModeCreator._get_value_or_default(limit_price, Ecmsc.LIMITS_PRICE_MIN.value) + max_price = AbstractTradingModeCreator._get_value_or_default(limit_price, Ecmsc.LIMITS_PRICE_MAX.value) # adapt digits if necessary - valid_quantity = AbstractOrderCreator._adapt_quantity(symbol_market, quantity) - valid_price = AbstractOrderCreator._adapt_price(symbol_market, price) + valid_quantity = AbstractTradingModeCreator._adapt_quantity(symbol_market, quantity) + valid_price = AbstractTradingModeCreator._adapt_price(symbol_market, price) total_order_price = valid_quantity * valid_price @@ -339,11 +339,11 @@ def _check_and_adapt_order_details_if_necessary(quantity, price, symbol_market): nb_orders_according_to_cost = total_order_price / max_cost nb_orders_according_to_quantity = valid_quantity / max_quantity if nb_orders_according_to_cost > nb_orders_according_to_quantity: - return AbstractOrderCreator._adapt_order_quantity_because_price(total_order_price, max_cost, price, - symbol_market) + return AbstractTradingModeCreator._adapt_order_quantity_because_price(total_order_price, max_cost, price, + symbol_market) else: - return AbstractOrderCreator._adapt_order_quantity_because_quantity(valid_quantity, max_quantity, - quantity, price, symbol_market) + return AbstractTradingModeCreator._adapt_order_quantity_because_quantity(valid_quantity, max_quantity, + quantity, price, symbol_market) else: # valid order that can be handled wy the exchange diff --git a/evaluator/evaluator_final.py b/trading/trader/modes/abstract_mode_decider.py similarity index 94% rename from evaluator/evaluator_final.py rename to trading/trader/modes/abstract_mode_decider.py index fe213ee3f..380c13447 100644 --- a/evaluator/evaluator_final.py +++ b/trading/trader/modes/abstract_mode_decider.py @@ -2,13 +2,13 @@ from queue import Queue from config.cst import EvaluatorStates, INIT_EVAL_NOTE -from trading.trader.modes.abstract_order_creator import AbstractOrderCreator +from trading.trader.modes.abstract_mode_creator import AbstractTradingModeCreator from tools.asynchronous_server import AsynchronousServer from tools.notifications import EvaluatorNotification from tools.evaluators_util import check_valid_eval_note -class FinalEvaluator(AsynchronousServer): +class AbstractTradingModeDecider(AsynchronousServer): def __init__(self, symbol_evaluator, exchange, symbol): super().__init__(self.finalize) self.symbol_evaluator = symbol_evaluator @@ -75,8 +75,8 @@ def create_final_state_orders(self, evaluator_notification): def _create_order_if_possible(self, evaluator_notification, trader): if trader.is_enabled(): with trader.get_portfolio() as pf: - if AbstractOrderCreator.can_create_order(self.symbol, self.exchange, self.state, pf): - FinalEvaluator._push_order_notification_if_possible( + if AbstractTradingModeCreator.can_create_order(self.symbol, self.exchange, self.state, pf): + AbstractTradingModeDecider._push_order_notification_if_possible( self.symbol_evaluator.get_evaluator_order_creator().create_new_order( self.final_eval, self.symbol, diff --git a/trading/trader/modes/abstract_trading_mode.py b/trading/trader/modes/abstract_trading_mode.py new file mode 100644 index 000000000..4b02c33a4 --- /dev/null +++ b/trading/trader/modes/abstract_trading_mode.py @@ -0,0 +1,18 @@ +class AbstractTradingMode: + def __init__(self, config): + self.config = config + + self.decider = None + self.creator = None + + def set_decider(self, decider): + self.decider = decider + + def set_creator(self, creator): + self.creator = creator + + def get_creator(self): + return self.creator + + def get_decider(self): + return self.decider From 859e75d68afb3edea8383495a4995bd92d758e99 Mon Sep 17 00:00:00 2001 From: Paul Bouquet Date: Sun, 3 Jun 2018 10:31:00 +0200 Subject: [PATCH 05/15] Implement daily trading mode --- .../trading_modes_tests/test_mode_decider.py | 2 +- .../modes/Default/daily_trading_mode.py | 87 ++++++++++++++++ trading/trader/modes/Default/investor_mode.py | 22 ++++- trading/trader/modes/abstract_mode_creator.py | 6 +- trading/trader/modes/abstract_mode_decider.py | 99 +++++-------------- trading/trader/modes/abstract_trading_mode.py | 5 + 6 files changed, 145 insertions(+), 76 deletions(-) create mode 100644 trading/trader/modes/Default/daily_trading_mode.py diff --git a/tests/unit_tests/trading_modes_tests/test_mode_decider.py b/tests/unit_tests/trading_modes_tests/test_mode_decider.py index 3a11b57dd..bb8badcc2 100644 --- a/tests/unit_tests/trading_modes_tests/test_mode_decider.py +++ b/tests/unit_tests/trading_modes_tests/test_mode_decider.py @@ -104,7 +104,7 @@ def test_prepare(): assert final_evaluator.state == EvaluatorStates.SHORT assert len(trader_inst.order_manager.order_list) == 2 # has stop loss final_evaluator.final_eval = None - final_evaluator._prepare() + final_evaluator._set_final_eval() assert final_evaluator.state == EvaluatorStates.SHORT # ensure did not change EvaluatorStates assert len(trader_inst.order_manager.order_list) == 2 # ensure did not change orders assert final_evaluator.final_eval == INIT_EVAL_NOTE diff --git a/trading/trader/modes/Default/daily_trading_mode.py b/trading/trader/modes/Default/daily_trading_mode.py new file mode 100644 index 000000000..cc41d29ae --- /dev/null +++ b/trading/trader/modes/Default/daily_trading_mode.py @@ -0,0 +1,87 @@ +from config.cst import EvaluatorStates, INIT_EVAL_NOTE +from tools.evaluators_util import check_valid_eval_note +from trading.trader.modes.abstract_mode_creator import AbstractTradingModeCreator +from trading.trader.modes.abstract_mode_decider import AbstractTradingModeDecider +from trading.trader.modes.abstract_trading_mode import AbstractTradingMode + + +class DailyTradingMode(AbstractTradingMode): + def __init__(self, config, symbol_evaluator, exchange, symbol): + super().__init__(config) + + self.set_creator(DailyTradingModeCreator(self)) + self.set_decider(DailyTradingModeDecider(self, symbol_evaluator, exchange, symbol)) + + +class DailyTradingModeCreator(AbstractTradingModeCreator): + def __init__(self, trading_mode): + super().__init__(trading_mode) + + +class DailyTradingModeDecider(AbstractTradingModeDecider): + def __init__(self, trading_mode, symbol_evaluator, exchange, symbol): + super().__init__(trading_mode, symbol_evaluator, exchange, symbol) + + def _set_final_eval(self): + strategies_analysis_note_counter = 0 + # Strategies analysis + for evaluated_strategies in self.symbol_evaluator.get_strategies_eval_list(self.exchange): + strategy_eval = evaluated_strategies.get_eval_note() + if check_valid_eval_note(strategy_eval): + self.final_eval += strategy_eval * evaluated_strategies.get_pertinence() + strategies_analysis_note_counter += evaluated_strategies.get_pertinence() + + if strategies_analysis_note_counter > 0: + self.final_eval /= strategies_analysis_note_counter + else: + self.final_eval = INIT_EVAL_NOTE + + def _get_delta_risk(self): + return self.RISK_THRESHOLD * self.symbol_evaluator.get_trader(self.exchange).get_risk() + + def _create_state(self): + delta_risk = self._get_delta_risk() + + if self.final_eval < self.VERY_LONG_THRESHOLD + delta_risk: + self._set_state(EvaluatorStates.VERY_LONG) + + elif self.final_eval < self.LONG_THRESHOLD + delta_risk: + self._set_state(EvaluatorStates.LONG) + + elif self.final_eval < self.NEUTRAL_THRESHOLD - delta_risk: + self._set_state(EvaluatorStates.NEUTRAL) + + elif self.final_eval < self.SHORT_THRESHOLD - delta_risk: + self._set_state(EvaluatorStates.SHORT) + + else: + self._set_state(EvaluatorStates.VERY_SHORT) + + def _set_state(self, new_state): + if new_state != self.state: + # previous_state = self.state + self.state = new_state + self.logger.info("{0} ** NEW FINAL STATE ** : {1}".format(self.symbol, self.state)) + + # if new state is not neutral --> cancel orders and create new else keep orders + if new_state is not EvaluatorStates.NEUTRAL: + + # cancel open orders + if self.symbol_evaluator.get_trader(self.exchange).is_enabled(): + self.symbol_evaluator.get_trader(self.exchange).cancel_open_orders(self.symbol) + if self.symbol_evaluator.get_trader_simulator(self.exchange).is_enabled(): + self.symbol_evaluator.get_trader_simulator(self.exchange).cancel_open_orders(self.symbol) + + # create notification + evaluator_notification = None + if self.notifier.enabled(): + evaluator_notification = self.notifier.notify_state_changed( + self.final_eval, + self.symbol_evaluator.get_crypto_currency_evaluator(), + self.symbol_evaluator.get_symbol(), + self.symbol_evaluator.get_trader(self.exchange), + self.state, + self.symbol_evaluator.get_matrix(self.exchange).get_matrix()) + + # call orders creation method + self.create_final_state_orders(evaluator_notification) diff --git a/trading/trader/modes/Default/investor_mode.py b/trading/trader/modes/Default/investor_mode.py index 9338ca32d..36b1408d4 100644 --- a/trading/trader/modes/Default/investor_mode.py +++ b/trading/trader/modes/Default/investor_mode.py @@ -1 +1,21 @@ -class InvestorMode() \ No newline at end of file +from trading.trader.modes.abstract_mode_creator import AbstractTradingModeCreator +from trading.trader.modes.abstract_mode_decider import AbstractTradingModeDecider +from trading.trader.modes.abstract_trading_mode import AbstractTradingMode + + +class InvestorMode(AbstractTradingMode): + def __init__(self, config, symbol_evaluator, exchange, symbol): + super().__init__(config) + + self.set_creator(InvestorModeCreator(self)) + self.set_decider(InvestorModeDecider(self, symbol_evaluator, exchange, symbol)) + + +class InvestorModeCreator(AbstractTradingModeCreator): + def __init__(self, trading_mode): + super().__init__(trading_mode) + + +class InvestorModeDecider(AbstractTradingModeDecider): + def __init__(self, trading_mode, symbol_evaluator, exchange, symbol): + super().__init__(trading_mode, symbol_evaluator, exchange, symbol) diff --git a/trading/trader/modes/abstract_mode_creator.py b/trading/trader/modes/abstract_mode_creator.py index 3317ef34e..2229d40a1 100644 --- a/trading/trader/modes/abstract_mode_creator.py +++ b/trading/trader/modes/abstract_mode_creator.py @@ -1,5 +1,6 @@ import logging import math +from abc import * from config.cst import * from config.cst import ExchangeConstantsMarketStatusColumns as Ecmsc @@ -7,7 +8,10 @@ class AbstractTradingModeCreator: - def __init__(self): + __metaclass__ = ABCMeta + + def __init__(self, trading_mode): + self.trading_mode = trading_mode self.MAX_SUM_RESULT = 2 self.STOP_LOSS_ORDER_MAX_PERCENT = 0.99 diff --git a/trading/trader/modes/abstract_mode_decider.py b/trading/trader/modes/abstract_mode_decider.py index 380c13447..dc910abcb 100644 --- a/trading/trader/modes/abstract_mode_decider.py +++ b/trading/trader/modes/abstract_mode_decider.py @@ -1,16 +1,18 @@ import logging +from abc import * from queue import Queue -from config.cst import EvaluatorStates, INIT_EVAL_NOTE -from trading.trader.modes.abstract_mode_creator import AbstractTradingModeCreator +from config.cst import INIT_EVAL_NOTE from tools.asynchronous_server import AsynchronousServer from tools.notifications import EvaluatorNotification -from tools.evaluators_util import check_valid_eval_note class AbstractTradingModeDecider(AsynchronousServer): - def __init__(self, symbol_evaluator, exchange, symbol): + __metaclass__ = ABCMeta + + def __init__(self, trading_mode, symbol_evaluator, exchange, symbol): super().__init__(self.finalize) + self.trading_mode = trading_mode self.symbol_evaluator = symbol_evaluator self.config = symbol_evaluator.get_config() self.final_eval = INIT_EVAL_NOTE @@ -31,39 +33,8 @@ def __init__(self, symbol_evaluator, exchange, symbol): self.notifier = EvaluatorNotification(self.config) self.queue = Queue() - def _set_state(self, new_state): - if new_state != self.state: - # previous_state = self.state - self.state = new_state - self.logger.info("{0} ** NEW FINAL STATE ** : {1}".format(self.symbol, self.state)) - - # if new state is not neutral --> cancel orders and create new else keep orders - if new_state is not EvaluatorStates.NEUTRAL: - - # cancel open orders - if self.symbol_evaluator.get_trader(self.exchange).is_enabled(): - self.symbol_evaluator.get_trader(self.exchange).cancel_open_orders(self.symbol) - if self.symbol_evaluator.get_trader_simulator(self.exchange).is_enabled(): - self.symbol_evaluator.get_trader_simulator(self.exchange).cancel_open_orders(self.symbol) - - # create notification - evaluator_notification = None - if self.notifier.enabled(): - evaluator_notification = self.notifier.notify_state_changed( - self.final_eval, - self.symbol_evaluator.get_crypto_currency_evaluator(), - self.symbol_evaluator.get_symbol(), - self.symbol_evaluator.get_trader(self.exchange), - self.state, - self.symbol_evaluator.get_matrix(self.exchange).get_matrix()) - - # call orders creation method - self.create_final_state_orders(evaluator_notification) - # create real and/or simulating orders in trader instances def create_final_state_orders(self, evaluator_notification): - # create orders - # simulated trader self._create_order_if_possible(evaluator_notification, self.symbol_evaluator.get_trader_simulator(self.exchange)) @@ -72,11 +43,12 @@ def create_final_state_orders(self, evaluator_notification): self._create_order_if_possible(evaluator_notification, self.symbol_evaluator.get_trader(self.exchange)) + # for each trader call the creator to check if order creation is possible and create it def _create_order_if_possible(self, evaluator_notification, trader): if trader.is_enabled(): with trader.get_portfolio() as pf: - if AbstractTradingModeCreator.can_create_order(self.symbol, self.exchange, self.state, pf): - AbstractTradingModeDecider._push_order_notification_if_possible( + if self.trading_mode.get_creator().can_create_order(self.symbol, self.exchange, self.state, pf): + self._push_order_notification_if_possible( self.symbol_evaluator.get_evaluator_order_creator().create_new_order( self.final_eval, self.symbol, @@ -98,47 +70,28 @@ def get_state(self): def get_final_eval(self): return self.final_eval - def _prepare(self): - strategies_analysis_note_counter = 0 - # Strategies analysis - for evaluated_strategies in self.symbol_evaluator.get_strategies_eval_list(self.exchange): - strategy_eval = evaluated_strategies.get_eval_note() - if check_valid_eval_note(strategy_eval): - self.final_eval += strategy_eval * evaluated_strategies.get_pertinence() - strategies_analysis_note_counter += evaluated_strategies.get_pertinence() - - if strategies_analysis_note_counter > 0: - self.final_eval /= strategies_analysis_note_counter - else: - self.final_eval = INIT_EVAL_NOTE - - def _get_delta_risk(self): - return self.RISK_THRESHOLD * self.symbol_evaluator.get_trader(self.exchange).get_risk() - - def _create_state(self): - delta_risk = self._get_delta_risk() - - if self.final_eval < self.VERY_LONG_THRESHOLD + delta_risk: - self._set_state(EvaluatorStates.VERY_LONG) - - elif self.final_eval < self.LONG_THRESHOLD + delta_risk: - self._set_state(EvaluatorStates.LONG) - - elif self.final_eval < self.NEUTRAL_THRESHOLD - delta_risk: - self._set_state(EvaluatorStates.NEUTRAL) - - elif self.final_eval < self.SHORT_THRESHOLD - delta_risk: - self._set_state(EvaluatorStates.SHORT) - - else: - self._set_state(EvaluatorStates.VERY_SHORT) - def finalize(self): # reset previous note self.final_eval = INIT_EVAL_NOTE - self._prepare() + self._set_final_eval() self._create_state() def stop(self): self.keep_running = False + + @abstractmethod + def _set_final_eval(self): + raise NotImplementedError("Set_final_eval not implemented") + + @abstractmethod + def _get_delta_risk(self): + raise NotImplementedError("Get_delta_risk not implemented") + + @abstractmethod + def _create_state(self): + raise NotImplementedError("Create_state not implemented") + + @abstractmethod + def _set_state(self, new_state): + raise NotImplementedError("Set_state not implemented") diff --git a/trading/trader/modes/abstract_trading_mode.py b/trading/trader/modes/abstract_trading_mode.py index 4b02c33a4..41610560b 100644 --- a/trading/trader/modes/abstract_trading_mode.py +++ b/trading/trader/modes/abstract_trading_mode.py @@ -1,4 +1,9 @@ +from abc import * + + class AbstractTradingMode: + __metaclass__ = ABCMeta + def __init__(self, config): self.config = config From 89afdb47bf995a8fed053f86d9b3a9ca0dab12c4 Mon Sep 17 00:00:00 2001 From: Paul Bouquet Date: Sun, 3 Jun 2018 10:51:35 +0200 Subject: [PATCH 06/15] Implement trading mode daily in symbol evaluator --- evaluator/symbol_evaluator.py | 22 +- .../modes/Default/daily_trading_mode.py | 184 ++++++++++++- trading/trader/modes/abstract_mode_creator.py | 241 +++--------------- trading/trader/modes/abstract_mode_decider.py | 2 +- 4 files changed, 236 insertions(+), 213 deletions(-) diff --git a/evaluator/symbol_evaluator.py b/evaluator/symbol_evaluator.py index 0d52e090a..a60300096 100644 --- a/evaluator/symbol_evaluator.py +++ b/evaluator/symbol_evaluator.py @@ -1,8 +1,7 @@ from config.cst import EvaluatorMatrixTypes from evaluator.evaluator_creator import EvaluatorCreator -from trading.trader.modes.abstract_mode_decider import AbstractTradingModeDecider from evaluator.evaluator_matrix import EvaluatorMatrix -from trading.trader.modes.abstract_mode_creator import AbstractTradingModeCreator +from trading.trader.modes.Default.daily_trading_mode import DailyTradingMode class SymbolEvaluator: @@ -15,13 +14,11 @@ def __init__(self, config, symbol, crypto_currency_evaluator): self.trader_simulators = None self.evaluator_thread_managers = {} - self.final_evaluators = {} + self.trading_mode_instances = {} self.matrices = {} self.strategies_eval_lists = {} self.finalize_enabled_list = {} - self.evaluator_order_creator = AbstractTradingModeCreator() - def set_traders(self, trader): self.traders = trader @@ -33,7 +30,10 @@ def add_evaluator_thread_manager(self, exchange, symbol, time_frame, evaluator_t self.evaluator_thread_managers[exchange.get_name()][time_frame] = evaluator_thread else: self.evaluator_thread_managers[exchange.get_name()] = {time_frame: evaluator_thread} - self.final_evaluators[exchange.get_name()] = AbstractTradingModeDecider(self, exchange, symbol) + + # TODO use config + self.trading_mode_instances[exchange.get_name()] = DailyTradingMode(self.config, self, exchange, symbol) + self.matrices[exchange.get_name()] = EvaluatorMatrix(self.config) self.strategies_eval_lists[exchange.get_name()] = EvaluatorCreator.create_strategies_eval_list(self.config) self.finalize_enabled_list[exchange.get_name()] = False @@ -52,7 +52,7 @@ def finalize(self, exchange): self._check_finalize(exchange) if self.finalize_enabled_list[exchange.get_name()]: - self.final_evaluators[exchange.get_name()].add_to_queue() + self.trading_mode_instances[exchange.get_name()].get_decider().add_to_queue() def _check_finalize(self, exchange): self.finalize_enabled_list[exchange.get_name()] = True @@ -67,10 +67,10 @@ def get_trader_simulator(self, exchange): return self.trader_simulators[exchange.get_name()] def get_final(self, exchange): - return self.final_evaluators[exchange.get_name()] + return self.trading_mode_instances[exchange.get_name()].get_decider() def has_exchange(self, exchange): - return exchange.get_name() in self.final_evaluators + return exchange.get_name() in self.trading_mode_instances def get_matrix(self, exchange): return self.matrices[exchange.get_name()] @@ -84,8 +84,8 @@ def get_config(self): def get_strategies_eval_list(self, exchange): return self.strategies_eval_lists[exchange.get_name()] - def get_evaluator_order_creator(self): - return self.evaluator_order_creator + def get_evaluator_order_creator(self, exchange): + return self.trading_mode_instances[exchange.get_name()].get_creator() def get_symbol(self): return self.symbol diff --git a/trading/trader/modes/Default/daily_trading_mode.py b/trading/trader/modes/Default/daily_trading_mode.py index cc41d29ae..23c2ee152 100644 --- a/trading/trader/modes/Default/daily_trading_mode.py +++ b/trading/trader/modes/Default/daily_trading_mode.py @@ -1,5 +1,8 @@ -from config.cst import EvaluatorStates, INIT_EVAL_NOTE +import logging + +from config.cst import EvaluatorStates, INIT_EVAL_NOTE, ORDER_CREATION_LAST_TRADES_TO_USE, TraderOrderType from tools.evaluators_util import check_valid_eval_note +from tools.symbol_util import split_symbol from trading.trader.modes.abstract_mode_creator import AbstractTradingModeCreator from trading.trader.modes.abstract_mode_decider import AbstractTradingModeDecider from trading.trader.modes.abstract_trading_mode import AbstractTradingMode @@ -17,6 +20,185 @@ class DailyTradingModeCreator(AbstractTradingModeCreator): def __init__(self, trading_mode): super().__init__(trading_mode) + """ + Starting point : self.SELL_LIMIT_ORDER_MIN_PERCENT or self.BUY_LIMIT_ORDER_MAX_PERCENT + 1 - abs(eval_note) --> confirmation level --> high : sell less expensive / buy more expensive + 1 - trader.get_risk() --> high risk : sell / buy closer to the current price + 1 - abs(eval_note) + 1 - trader.get_risk() --> result between 0 and 2 --> self.MAX_SUM_RESULT + self.QUANTITY_ATTENUATION --> try to contains the result between self.XXX_MIN_PERCENT and self.XXX_MAX_PERCENT + """ + + def _get_limit_price_from_risk(self, eval_note, trader): + if eval_note > 0: + factor = self.SELL_LIMIT_ORDER_MIN_PERCENT + \ + ((1 - abs(eval_note) + 1 - trader.get_risk()) * self.LIMIT_ORDER_ATTENUATION) + return AbstractTradingModeCreator._check_factor(self.SELL_LIMIT_ORDER_MIN_PERCENT, + self.SELL_LIMIT_ORDER_MAX_PERCENT, + factor) + else: + factor = self.BUY_LIMIT_ORDER_MAX_PERCENT - \ + ((1 - abs(eval_note) + 1 - trader.get_risk()) * self.LIMIT_ORDER_ATTENUATION) + return AbstractTradingModeCreator._check_factor(self.BUY_LIMIT_ORDER_MIN_PERCENT, + self.BUY_LIMIT_ORDER_MAX_PERCENT, + factor) + + """ + Starting point : self.STOP_LOSS_ORDER_MAX_PERCENT + trader.get_risk() --> low risk : stop level close to the current price + self.STOP_LOSS_ORDER_ATTENUATION --> try to contains the result between self.STOP_LOSS_ORDER_MIN_PERCENT and self.STOP_LOSS_ORDER_MAX_PERCENT + """ + + def _get_stop_price_from_risk(self, trader): + factor = self.STOP_LOSS_ORDER_MAX_PERCENT - (trader.get_risk() * self.STOP_LOSS_ORDER_ATTENUATION) + return AbstractTradingModeCreator._check_factor(self.STOP_LOSS_ORDER_MIN_PERCENT, + self.STOP_LOSS_ORDER_MAX_PERCENT, + factor) + + """ + Starting point : self.QUANTITY_MIN_PERCENT + abs(eval_note) --> confirmation level --> high : sell/buy more quantity + trader.get_risk() --> high risk : sell / buy more quantity + abs(eval_note) + trader.get_risk() --> result between 0 and 2 --> self.MAX_SUM_RESULT + self.QUANTITY_ATTENUATION --> try to contains the result between self.QUANTITY_MIN_PERCENT and self.QUANTITY_MAX_PERCENT + """ + + def _get_limit_quantity_from_risk(self, eval_note, trader, quantity): + factor = self.QUANTITY_MIN_PERCENT + ((abs(eval_note) + trader.get_risk()) * self.QUANTITY_ATTENUATION) + return AbstractTradingModeCreator._check_factor(self.QUANTITY_MIN_PERCENT, + self.QUANTITY_MAX_PERCENT, + factor) * quantity + + """ + Starting point : self.QUANTITY_MARKET_MIN_PERCENT + abs(eval_note) --> confirmation level --> high : sell/buy more quantity + trader.get_risk() --> high risk : sell / buy more quantity + abs(eval_note) + trader.get_risk() --> result between 0 and 2 --> self.MAX_SUM_RESULT + self.QUANTITY_MARKET_ATTENUATION --> try to contains the result between self.QUANTITY_MARKET_MIN_PERCENT and self.QUANTITY_MARKET_MAX_PERCENT + """ + + def _get_market_quantity_from_risk(self, eval_note, trader, quantity, buy=False): + factor = self.QUANTITY_MARKET_MIN_PERCENT + ( + (abs(eval_note) + trader.get_risk()) * self.QUANTITY_MARKET_ATTENUATION) + + # if buy market --> limit market usage + if buy: + factor *= self.QUANTITY_BUY_MARKET_ATTENUATION + + return AbstractTradingModeCreator._check_factor(self.QUANTITY_MARKET_MIN_PERCENT, + self.QUANTITY_MARKET_MAX_PERCENT, + factor) * quantity + + # creates a new order (or multiple split orders), always check EvaluatorOrderCreator.can_create_order() first. + def create_new_order(self, eval_note, symbol, exchange, trader, portfolio, state): + try: + last_prices = exchange.get_recent_trades(symbol) + reference_sum = 0 + + for last_price in last_prices[-ORDER_CREATION_LAST_TRADES_TO_USE:]: + reference_sum += float(last_price["price"]) + + reference = reference_sum / ORDER_CREATION_LAST_TRADES_TO_USE + + currency, market = split_symbol(symbol) + + current_portfolio = portfolio.get_currency_portfolio(currency) + current_market_quantity = portfolio.get_currency_portfolio(market) + + market_quantity = current_market_quantity / reference + + price = reference + symbol_market = exchange.get_market_status(symbol) + + created_orders = [] + + if state == EvaluatorStates.VERY_SHORT: + quantity = self._get_market_quantity_from_risk(eval_note, + trader, + current_portfolio) + for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, price, + symbol_market): + market = trader.create_order_instance(order_type=TraderOrderType.SELL_MARKET, + symbol=symbol, + current_price=order_price, + quantity=order_quantity, + price=order_price) + trader.create_order(market, portfolio) + created_orders.append(market) + return created_orders + + elif state == EvaluatorStates.SHORT: + quantity = self._get_limit_quantity_from_risk(eval_note, + trader, + current_portfolio) + limit_price = AbstractTradingModeCreator \ + ._adapt_price(symbol_market, price * self._get_limit_price_from_risk(eval_note, trader)) + stop_price = AbstractTradingModeCreator \ + ._adapt_price(symbol_market, price * self._get_stop_price_from_risk(trader)) + for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, + limit_price, + symbol_market): + limit = trader.create_order_instance(order_type=TraderOrderType.SELL_LIMIT, + symbol=symbol, + current_price=price, + quantity=order_quantity, + price=order_price) + updated_limit = trader.create_order(limit, portfolio) + created_orders.append(updated_limit) + + stop = trader.create_order_instance(order_type=TraderOrderType.STOP_LOSS, + symbol=symbol, + current_price=price, + quantity=order_quantity, + price=stop_price, + linked_to=updated_limit) + trader.create_order(stop, portfolio) + return created_orders + + elif state == EvaluatorStates.NEUTRAL: + pass + + # TODO : stop loss + elif state == EvaluatorStates.LONG: + quantity = self._get_limit_quantity_from_risk(eval_note, + trader, + market_quantity) + limit_price = AbstractTradingModeCreator \ + ._adapt_price(symbol_market, price * self._get_limit_price_from_risk(eval_note, trader)) + for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, + limit_price, + symbol_market): + limit = trader.create_order_instance(order_type=TraderOrderType.BUY_LIMIT, + symbol=symbol, + current_price=price, + quantity=order_quantity, + price=order_price) + trader.create_order(limit, portfolio) + created_orders.append(limit) + return created_orders + + elif state == EvaluatorStates.VERY_LONG: + quantity = self._get_market_quantity_from_risk(eval_note, + trader, + market_quantity, + True) + for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, price, + symbol_market): + market = trader.create_order_instance(order_type=TraderOrderType.BUY_MARKET, + symbol=symbol, + current_price=order_price, + quantity=order_quantity, + price=order_price) + trader.create_order(market, portfolio) + created_orders.append(market) + return created_orders + + # if nothing go returned, return None + return None + + except Exception as e: + logging.getLogger(self.__class__.__name__).error("Failed to create order : {0}".format(e)) + return None + class DailyTradingModeDecider(AbstractTradingModeDecider): def __init__(self, trading_mode, symbol_evaluator, exchange, symbol): diff --git a/trading/trader/modes/abstract_mode_creator.py b/trading/trader/modes/abstract_mode_creator.py index 2229d40a1..5664144c7 100644 --- a/trading/trader/modes/abstract_mode_creator.py +++ b/trading/trader/modes/abstract_mode_creator.py @@ -1,4 +1,3 @@ -import logging import math from abc import * @@ -35,137 +34,6 @@ def __init__(self, trading_mode): self.LIMIT_ORDER_ATTENUATION = (self.BUY_LIMIT_ORDER_MAX_PERCENT - self.BUY_LIMIT_ORDER_MIN_PERCENT)\ / self.MAX_SUM_RESULT - @staticmethod - def can_create_order(symbol, exchange, state, portfolio): - currency, market = split_symbol(symbol) - - # get symbol min amount when creating order - symbol_limit = exchange.get_market_status(symbol)[Ecmsc.LIMITS.value] - symbol_min_amount = symbol_limit[Ecmsc.LIMITS_AMOUNT.value][Ecmsc.LIMITS_AMOUNT_MIN.value] - order_min_amount = symbol_limit[Ecmsc.LIMITS_COST.value][Ecmsc.LIMITS_COST_MIN.value] - - # short cases => sell => need this currency - if state == EvaluatorStates.VERY_SHORT or state == EvaluatorStates.SHORT: - return portfolio.get_currency_portfolio(currency) > symbol_min_amount - - # long cases => buy => need money(aka other currency in the pair) to buy this currency - elif state == EvaluatorStates.LONG or state == EvaluatorStates.VERY_LONG: - return portfolio.get_currency_portfolio(market) > order_min_amount - - # other cases like neutral state or unfulfilled previous conditions - return False - - # creates a new order (or multiple split orders), always check EvaluatorOrderCreator.can_create_order() first. - def create_new_order(self, eval_note, symbol, exchange, trader, portfolio, state): - try: - last_prices = exchange.get_recent_trades(symbol) - reference_sum = 0 - - for last_price in last_prices[-ORDER_CREATION_LAST_TRADES_TO_USE:]: - reference_sum += float(last_price["price"]) - - reference = reference_sum / ORDER_CREATION_LAST_TRADES_TO_USE - - currency, market = split_symbol(symbol) - - current_portfolio = portfolio.get_currency_portfolio(currency) - current_market_quantity = portfolio.get_currency_portfolio(market) - - market_quantity = current_market_quantity / reference - - price = reference - symbol_market = exchange.get_market_status(symbol) - - created_orders = [] - - if state == EvaluatorStates.VERY_SHORT: - quantity = self._get_market_quantity_from_risk(eval_note, - trader, - current_portfolio) - for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, price, - symbol_market): - market = trader.create_order_instance(order_type=TraderOrderType.SELL_MARKET, - symbol=symbol, - current_price=order_price, - quantity=order_quantity, - price=order_price) - trader.create_order(market, portfolio) - created_orders.append(market) - return created_orders - - elif state == EvaluatorStates.SHORT: - quantity = self._get_limit_quantity_from_risk(eval_note, - trader, - current_portfolio) - limit_price = AbstractTradingModeCreator\ - ._adapt_price(symbol_market, price * self._get_limit_price_from_risk(eval_note, trader)) - stop_price = AbstractTradingModeCreator \ - ._adapt_price(symbol_market, price * self._get_stop_price_from_risk(trader)) - for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, - limit_price, - symbol_market): - limit = trader.create_order_instance(order_type=TraderOrderType.SELL_LIMIT, - symbol=symbol, - current_price=price, - quantity=order_quantity, - price=order_price) - updated_limit = trader.create_order(limit, portfolio) - created_orders.append(updated_limit) - - stop = trader.create_order_instance(order_type=TraderOrderType.STOP_LOSS, - symbol=symbol, - current_price=price, - quantity=order_quantity, - price=stop_price, - linked_to=updated_limit) - trader.create_order(stop, portfolio) - return created_orders - - elif state == EvaluatorStates.NEUTRAL: - pass - - # TODO : stop loss - elif state == EvaluatorStates.LONG: - quantity = self._get_limit_quantity_from_risk(eval_note, - trader, - market_quantity) - limit_price = AbstractTradingModeCreator\ - ._adapt_price(symbol_market, price * self._get_limit_price_from_risk(eval_note, trader)) - for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, - limit_price, - symbol_market): - limit = trader.create_order_instance(order_type=TraderOrderType.BUY_LIMIT, - symbol=symbol, - current_price=price, - quantity=order_quantity, - price=order_price) - trader.create_order(limit, portfolio) - created_orders.append(limit) - return created_orders - - elif state == EvaluatorStates.VERY_LONG: - quantity = self._get_market_quantity_from_risk(eval_note, - trader, - market_quantity, - True) - for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, price, - symbol_market): - market = trader.create_order_instance(order_type=TraderOrderType.BUY_MARKET, - symbol=symbol, - current_price=order_price, - quantity=order_quantity, - price=order_price) - trader.create_order(market, portfolio) - created_orders.append(market) - return created_orders - - # if nothing go returned, return None - return None - - except Exception as e: - logging.getLogger(self.__class__.__name__).error("Failed to create order : {0}".format(e)) - return None - @staticmethod def _check_factor(min_val, max_val, factor): if factor > max_val: @@ -175,74 +43,6 @@ def _check_factor(min_val, max_val, factor): else: return factor - """ - Starting point : self.SELL_LIMIT_ORDER_MIN_PERCENT or self.BUY_LIMIT_ORDER_MAX_PERCENT - 1 - abs(eval_note) --> confirmation level --> high : sell less expensive / buy more expensive - 1 - trader.get_risk() --> high risk : sell / buy closer to the current price - 1 - abs(eval_note) + 1 - trader.get_risk() --> result between 0 and 2 --> self.MAX_SUM_RESULT - self.QUANTITY_ATTENUATION --> try to contains the result between self.XXX_MIN_PERCENT and self.XXX_MAX_PERCENT - """ - - def _get_limit_price_from_risk(self, eval_note, trader): - if eval_note > 0: - factor = self.SELL_LIMIT_ORDER_MIN_PERCENT + \ - ((1 - abs(eval_note) + 1 - trader.get_risk()) * self.LIMIT_ORDER_ATTENUATION) - return AbstractTradingModeCreator._check_factor(self.SELL_LIMIT_ORDER_MIN_PERCENT, - self.SELL_LIMIT_ORDER_MAX_PERCENT, - factor) - else: - factor = self.BUY_LIMIT_ORDER_MAX_PERCENT - \ - ((1 - abs(eval_note) + 1 - trader.get_risk()) * self.LIMIT_ORDER_ATTENUATION) - return AbstractTradingModeCreator._check_factor(self.BUY_LIMIT_ORDER_MIN_PERCENT, - self.BUY_LIMIT_ORDER_MAX_PERCENT, - factor) - - """ - Starting point : self.STOP_LOSS_ORDER_MAX_PERCENT - trader.get_risk() --> low risk : stop level close to the current price - self.STOP_LOSS_ORDER_ATTENUATION --> try to contains the result between self.STOP_LOSS_ORDER_MIN_PERCENT and self.STOP_LOSS_ORDER_MAX_PERCENT - """ - - def _get_stop_price_from_risk(self, trader): - factor = self.STOP_LOSS_ORDER_MAX_PERCENT - (trader.get_risk() * self.STOP_LOSS_ORDER_ATTENUATION) - return AbstractTradingModeCreator._check_factor(self.STOP_LOSS_ORDER_MIN_PERCENT, - self.STOP_LOSS_ORDER_MAX_PERCENT, - factor) - - """ - Starting point : self.QUANTITY_MIN_PERCENT - abs(eval_note) --> confirmation level --> high : sell/buy more quantity - trader.get_risk() --> high risk : sell / buy more quantity - abs(eval_note) + trader.get_risk() --> result between 0 and 2 --> self.MAX_SUM_RESULT - self.QUANTITY_ATTENUATION --> try to contains the result between self.QUANTITY_MIN_PERCENT and self.QUANTITY_MAX_PERCENT - """ - - def _get_limit_quantity_from_risk(self, eval_note, trader, quantity): - factor = self.QUANTITY_MIN_PERCENT + ((abs(eval_note) + trader.get_risk()) * self.QUANTITY_ATTENUATION) - return AbstractTradingModeCreator._check_factor(self.QUANTITY_MIN_PERCENT, - self.QUANTITY_MAX_PERCENT, - factor) * quantity - - """ - Starting point : self.QUANTITY_MARKET_MIN_PERCENT - abs(eval_note) --> confirmation level --> high : sell/buy more quantity - trader.get_risk() --> high risk : sell / buy more quantity - abs(eval_note) + trader.get_risk() --> result between 0 and 2 --> self.MAX_SUM_RESULT - self.QUANTITY_MARKET_ATTENUATION --> try to contains the result between self.QUANTITY_MARKET_MIN_PERCENT and self.QUANTITY_MARKET_MAX_PERCENT - """ - - def _get_market_quantity_from_risk(self, eval_note, trader, quantity, buy=False): - factor = self.QUANTITY_MARKET_MIN_PERCENT + ( - (abs(eval_note) + trader.get_risk()) * self.QUANTITY_MARKET_ATTENUATION) - - # if buy market --> limit market usage - if buy: - factor *= self.QUANTITY_BUY_MARKET_ATTENUATION - - return AbstractTradingModeCreator._check_factor(self.QUANTITY_MARKET_MIN_PERCENT, - self.QUANTITY_MARKET_MAX_PERCENT, - factor) * quantity - @staticmethod def _trunc_with_n_decimal_digits(value, digits): # force exact representation @@ -352,3 +152,44 @@ def _check_and_adapt_order_details_if_necessary(quantity, price, symbol_market): else: # valid order that can be handled wy the exchange return [(valid_quantity, valid_price)] + + @staticmethod + # Can be overwritten + def can_create_order(symbol, exchange, state, portfolio): + currency, market = split_symbol(symbol) + + # get symbol min amount when creating order + symbol_limit = exchange.get_market_status(symbol)[Ecmsc.LIMITS.value] + symbol_min_amount = symbol_limit[Ecmsc.LIMITS_AMOUNT.value][Ecmsc.LIMITS_AMOUNT_MIN.value] + order_min_amount = symbol_limit[Ecmsc.LIMITS_COST.value][Ecmsc.LIMITS_COST_MIN.value] + + # short cases => sell => need this currency + if state == EvaluatorStates.VERY_SHORT or state == EvaluatorStates.SHORT: + return portfolio.get_currency_portfolio(currency) > symbol_min_amount + + # long cases => buy => need money(aka other currency in the pair) to buy this currency + elif state == EvaluatorStates.LONG or state == EvaluatorStates.VERY_LONG: + return portfolio.get_currency_portfolio(market) > order_min_amount + + # other cases like neutral state or unfulfilled previous conditions + return False + + @abstractmethod + def create_new_order(self, eval_note, symbol, exchange, trader, portfolio, state): + raise NotImplementedError("Create_new_order not implemented") + + @abstractmethod + def _get_limit_price_from_risk(self, eval_note, trader): + raise NotImplementedError("Set_final_eval not implemented") + + @abstractmethod + def _get_stop_price_from_risk(self, trader): + raise NotImplementedError("Set_final_eval not implemented") + + @abstractmethod + def _get_limit_quantity_from_risk(self, eval_note, trader, quantity): + raise NotImplementedError("Set_final_eval not implemented") + + @abstractmethod + def _get_market_quantity_from_risk(self, eval_note, trader, quantity, buy=False): + raise NotImplementedError("Set_final_eval not implemented") diff --git a/trading/trader/modes/abstract_mode_decider.py b/trading/trader/modes/abstract_mode_decider.py index dc910abcb..6897e7b65 100644 --- a/trading/trader/modes/abstract_mode_decider.py +++ b/trading/trader/modes/abstract_mode_decider.py @@ -49,7 +49,7 @@ def _create_order_if_possible(self, evaluator_notification, trader): with trader.get_portfolio() as pf: if self.trading_mode.get_creator().can_create_order(self.symbol, self.exchange, self.state, pf): self._push_order_notification_if_possible( - self.symbol_evaluator.get_evaluator_order_creator().create_new_order( + self.symbol_evaluator.get_evaluator_order_creator(self.exchange).create_new_order( self.final_eval, self.symbol, self.exchange, From 5c80043c160f6af0f355ff1e9aca180d2fafe241 Mon Sep 17 00:00:00 2001 From: Paul Bouquet Date: Sun, 3 Jun 2018 11:14:53 +0200 Subject: [PATCH 07/15] Implement trading mode load from symbol evaluator --- config/cst.py | 1 + config/default_config.json | 4 +++- evaluator/symbol_evaluator.py | 20 +++++++++++++++--- .../modes/Default/daily_trading_mode.py | 21 ++++++++----------- 4 files changed, 30 insertions(+), 16 deletions(-) diff --git a/config/cst.py b/config/cst.py index ab9e6163c..5d513edab 100644 --- a/config/cst.py +++ b/config/cst.py @@ -45,6 +45,7 @@ CONFIG_SIMULATOR = "trader_simulator" CONFIG_STARTING_PORTFOLIO = "starting_portfolio" CONFIG_TRADER_RISK = "risk" +CONFIG_TRADER_MODE = "mode" CONFIG_TRADER_RISK_MIN = 0.05 CONFIG_TRADER_RISK_MAX = 1 ORDER_REFRESHER_TIME = 15 diff --git a/config/default_config.json b/config/default_config.json index 314b6a51e..dbadda4a9 100644 --- a/config/default_config.json +++ b/config/default_config.json @@ -14,7 +14,9 @@ }, "trader":{ "enabled": false, - "risk": 0.5 + "risk": 0.5, + "reference_market": "BTC", + "mode": "DailyTradingMode" }, "trader_simulator":{ "enabled": true, diff --git a/evaluator/symbol_evaluator.py b/evaluator/symbol_evaluator.py index a60300096..9d4db5c6b 100644 --- a/evaluator/symbol_evaluator.py +++ b/evaluator/symbol_evaluator.py @@ -1,7 +1,10 @@ -from config.cst import EvaluatorMatrixTypes +import inspect +import logging + +from config.cst import EvaluatorMatrixTypes, CONFIG_TRADER_MODE from evaluator.evaluator_creator import EvaluatorCreator from evaluator.evaluator_matrix import EvaluatorMatrix -from trading.trader.modes.Default.daily_trading_mode import DailyTradingMode +from trading.trader import modes class SymbolEvaluator: @@ -12,6 +15,7 @@ def __init__(self, config, symbol, crypto_currency_evaluator): self.config = config self.traders = None self.trader_simulators = None + self.logger = logging.getLogger("{0} {1}".format(self.symbol, self.__class__.__name__)) self.evaluator_thread_managers = {} self.trading_mode_instances = {} @@ -19,12 +23,21 @@ def __init__(self, config, symbol, crypto_currency_evaluator): self.strategies_eval_lists = {} self.finalize_enabled_list = {} + self.trading_mode_class = self.get_trading_mode_class() + def set_traders(self, trader): self.traders = trader def set_trader_simulators(self, simulator): self.trader_simulators = simulator + def get_trading_mode_class(self): + if CONFIG_TRADER_MODE in self.config: + if CONFIG_TRADER_MODE in inspect.getmembers(modes): + return CONFIG_TRADER_MODE + + raise Exception("Please specify a valid trading mode in your config file (trader -> mode)") + def add_evaluator_thread_manager(self, exchange, symbol, time_frame, evaluator_thread): if exchange.get_name() in self.evaluator_thread_managers: self.evaluator_thread_managers[exchange.get_name()][time_frame] = evaluator_thread @@ -32,7 +45,8 @@ def add_evaluator_thread_manager(self, exchange, symbol, time_frame, evaluator_t self.evaluator_thread_managers[exchange.get_name()] = {time_frame: evaluator_thread} # TODO use config - self.trading_mode_instances[exchange.get_name()] = DailyTradingMode(self.config, self, exchange, symbol) + self.trading_mode_instances[exchange.get_name()] = self.trading_mode_class(self.config, self, exchange, + symbol) self.matrices[exchange.get_name()] = EvaluatorMatrix(self.config) self.strategies_eval_lists[exchange.get_name()] = EvaluatorCreator.create_strategies_eval_list(self.config) diff --git a/trading/trader/modes/Default/daily_trading_mode.py b/trading/trader/modes/Default/daily_trading_mode.py index 23c2ee152..6028b4e0c 100644 --- a/trading/trader/modes/Default/daily_trading_mode.py +++ b/trading/trader/modes/Default/daily_trading_mode.py @@ -32,13 +32,13 @@ def _get_limit_price_from_risk(self, eval_note, trader): if eval_note > 0: factor = self.SELL_LIMIT_ORDER_MIN_PERCENT + \ ((1 - abs(eval_note) + 1 - trader.get_risk()) * self.LIMIT_ORDER_ATTENUATION) - return AbstractTradingModeCreator._check_factor(self.SELL_LIMIT_ORDER_MIN_PERCENT, + return self._check_factor(self.SELL_LIMIT_ORDER_MIN_PERCENT, self.SELL_LIMIT_ORDER_MAX_PERCENT, factor) else: factor = self.BUY_LIMIT_ORDER_MAX_PERCENT - \ ((1 - abs(eval_note) + 1 - trader.get_risk()) * self.LIMIT_ORDER_ATTENUATION) - return AbstractTradingModeCreator._check_factor(self.BUY_LIMIT_ORDER_MIN_PERCENT, + return self._check_factor(self.BUY_LIMIT_ORDER_MIN_PERCENT, self.BUY_LIMIT_ORDER_MAX_PERCENT, factor) @@ -50,7 +50,7 @@ def _get_limit_price_from_risk(self, eval_note, trader): def _get_stop_price_from_risk(self, trader): factor = self.STOP_LOSS_ORDER_MAX_PERCENT - (trader.get_risk() * self.STOP_LOSS_ORDER_ATTENUATION) - return AbstractTradingModeCreator._check_factor(self.STOP_LOSS_ORDER_MIN_PERCENT, + return self._check_factor(self.STOP_LOSS_ORDER_MIN_PERCENT, self.STOP_LOSS_ORDER_MAX_PERCENT, factor) @@ -64,7 +64,7 @@ def _get_stop_price_from_risk(self, trader): def _get_limit_quantity_from_risk(self, eval_note, trader, quantity): factor = self.QUANTITY_MIN_PERCENT + ((abs(eval_note) + trader.get_risk()) * self.QUANTITY_ATTENUATION) - return AbstractTradingModeCreator._check_factor(self.QUANTITY_MIN_PERCENT, + return self._check_factor(self.QUANTITY_MIN_PERCENT, self.QUANTITY_MAX_PERCENT, factor) * quantity @@ -80,11 +80,11 @@ def _get_market_quantity_from_risk(self, eval_note, trader, quantity, buy=False) factor = self.QUANTITY_MARKET_MIN_PERCENT + ( (abs(eval_note) + trader.get_risk()) * self.QUANTITY_MARKET_ATTENUATION) - # if buy market --> limit market usage + # if buy market --> limit market usacge if buy: factor *= self.QUANTITY_BUY_MARKET_ATTENUATION - return AbstractTradingModeCreator._check_factor(self.QUANTITY_MARKET_MIN_PERCENT, + return self._check_factor(self.QUANTITY_MARKET_MIN_PERCENT, self.QUANTITY_MARKET_MAX_PERCENT, factor) * quantity @@ -130,10 +130,8 @@ def create_new_order(self, eval_note, symbol, exchange, trader, portfolio, state quantity = self._get_limit_quantity_from_risk(eval_note, trader, current_portfolio) - limit_price = AbstractTradingModeCreator \ - ._adapt_price(symbol_market, price * self._get_limit_price_from_risk(eval_note, trader)) - stop_price = AbstractTradingModeCreator \ - ._adapt_price(symbol_market, price * self._get_stop_price_from_risk(trader)) + limit_price = self._adapt_price(symbol_market, price * self._get_limit_price_from_risk(eval_note, trader)) + stop_price = self._adapt_price(symbol_market, price * self._get_stop_price_from_risk(trader)) for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, limit_price, symbol_market): @@ -162,8 +160,7 @@ def create_new_order(self, eval_note, symbol, exchange, trader, portfolio, state quantity = self._get_limit_quantity_from_risk(eval_note, trader, market_quantity) - limit_price = AbstractTradingModeCreator \ - ._adapt_price(symbol_market, price * self._get_limit_price_from_risk(eval_note, trader)) + limit_price = self._adapt_price(symbol_market, price * self._get_limit_price_from_risk(eval_note, trader)) for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, limit_price, symbol_market): From 955d0b8636d8ee86d028af42e9db78e9c5f3cc55 Mon Sep 17 00:00:00 2001 From: Paul Bouquet Date: Sun, 3 Jun 2018 11:24:33 +0200 Subject: [PATCH 08/15] Load trading mode from config --- evaluator/symbol_evaluator.py | 8 ++++---- trading/trader/modes/Default/__init__.py | 1 + trading/trader/modes/__init__.py | 2 ++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/evaluator/symbol_evaluator.py b/evaluator/symbol_evaluator.py index 9d4db5c6b..e6c919407 100644 --- a/evaluator/symbol_evaluator.py +++ b/evaluator/symbol_evaluator.py @@ -1,7 +1,7 @@ import inspect import logging -from config.cst import EvaluatorMatrixTypes, CONFIG_TRADER_MODE +from config.cst import EvaluatorMatrixTypes, CONFIG_TRADER_MODE, CONFIG_TRADER from evaluator.evaluator_creator import EvaluatorCreator from evaluator.evaluator_matrix import EvaluatorMatrix from trading.trader import modes @@ -32,9 +32,9 @@ def set_trader_simulators(self, simulator): self.trader_simulators = simulator def get_trading_mode_class(self): - if CONFIG_TRADER_MODE in self.config: - if CONFIG_TRADER_MODE in inspect.getmembers(modes): - return CONFIG_TRADER_MODE + if CONFIG_TRADER in self.config and CONFIG_TRADER_MODE in self.config[CONFIG_TRADER]: + if any(m[0] == self.config[CONFIG_TRADER][CONFIG_TRADER_MODE] for m in inspect.getmembers(modes)): + return getattr(modes, self.config[CONFIG_TRADER][CONFIG_TRADER_MODE]) raise Exception("Please specify a valid trading mode in your config file (trader -> mode)") diff --git a/trading/trader/modes/Default/__init__.py b/trading/trader/modes/Default/__init__.py index e69de29bb..a5a2f7cc6 100644 --- a/trading/trader/modes/Default/__init__.py +++ b/trading/trader/modes/Default/__init__.py @@ -0,0 +1 @@ +from .daily_trading_mode import * \ No newline at end of file diff --git a/trading/trader/modes/__init__.py b/trading/trader/modes/__init__.py index e69de29bb..89b5d6058 100644 --- a/trading/trader/modes/__init__.py +++ b/trading/trader/modes/__init__.py @@ -0,0 +1,2 @@ +from .Default import * +from .Advanced import * \ No newline at end of file From b48276b13495348b3de17ca55c69c0c47f188e48 Mon Sep 17 00:00:00 2001 From: Paul Bouquet Date: Sun, 3 Jun 2018 11:26:51 +0200 Subject: [PATCH 09/15] Remove trading mode tentacle --- trading/trader/modes/Default/__init__.py | 1 - .../modes/Default/daily_trading_mode.py | 266 ------------------ .../modes/Default/high_frequency_mode.py | 0 trading/trader/modes/Default/investor_mode.py | 21 -- .../trader/modes/Default/objective_mode.py | 0 .../trader/modes/Default/opportunity_mode.py | 0 .../trader/modes/Default/safe_profit_mode.py | 0 7 files changed, 288 deletions(-) delete mode 100644 trading/trader/modes/Default/__init__.py delete mode 100644 trading/trader/modes/Default/daily_trading_mode.py delete mode 100644 trading/trader/modes/Default/high_frequency_mode.py delete mode 100644 trading/trader/modes/Default/investor_mode.py delete mode 100644 trading/trader/modes/Default/objective_mode.py delete mode 100644 trading/trader/modes/Default/opportunity_mode.py delete mode 100644 trading/trader/modes/Default/safe_profit_mode.py diff --git a/trading/trader/modes/Default/__init__.py b/trading/trader/modes/Default/__init__.py deleted file mode 100644 index a5a2f7cc6..000000000 --- a/trading/trader/modes/Default/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from .daily_trading_mode import * \ No newline at end of file diff --git a/trading/trader/modes/Default/daily_trading_mode.py b/trading/trader/modes/Default/daily_trading_mode.py deleted file mode 100644 index 6028b4e0c..000000000 --- a/trading/trader/modes/Default/daily_trading_mode.py +++ /dev/null @@ -1,266 +0,0 @@ -import logging - -from config.cst import EvaluatorStates, INIT_EVAL_NOTE, ORDER_CREATION_LAST_TRADES_TO_USE, TraderOrderType -from tools.evaluators_util import check_valid_eval_note -from tools.symbol_util import split_symbol -from trading.trader.modes.abstract_mode_creator import AbstractTradingModeCreator -from trading.trader.modes.abstract_mode_decider import AbstractTradingModeDecider -from trading.trader.modes.abstract_trading_mode import AbstractTradingMode - - -class DailyTradingMode(AbstractTradingMode): - def __init__(self, config, symbol_evaluator, exchange, symbol): - super().__init__(config) - - self.set_creator(DailyTradingModeCreator(self)) - self.set_decider(DailyTradingModeDecider(self, symbol_evaluator, exchange, symbol)) - - -class DailyTradingModeCreator(AbstractTradingModeCreator): - def __init__(self, trading_mode): - super().__init__(trading_mode) - - """ - Starting point : self.SELL_LIMIT_ORDER_MIN_PERCENT or self.BUY_LIMIT_ORDER_MAX_PERCENT - 1 - abs(eval_note) --> confirmation level --> high : sell less expensive / buy more expensive - 1 - trader.get_risk() --> high risk : sell / buy closer to the current price - 1 - abs(eval_note) + 1 - trader.get_risk() --> result between 0 and 2 --> self.MAX_SUM_RESULT - self.QUANTITY_ATTENUATION --> try to contains the result between self.XXX_MIN_PERCENT and self.XXX_MAX_PERCENT - """ - - def _get_limit_price_from_risk(self, eval_note, trader): - if eval_note > 0: - factor = self.SELL_LIMIT_ORDER_MIN_PERCENT + \ - ((1 - abs(eval_note) + 1 - trader.get_risk()) * self.LIMIT_ORDER_ATTENUATION) - return self._check_factor(self.SELL_LIMIT_ORDER_MIN_PERCENT, - self.SELL_LIMIT_ORDER_MAX_PERCENT, - factor) - else: - factor = self.BUY_LIMIT_ORDER_MAX_PERCENT - \ - ((1 - abs(eval_note) + 1 - trader.get_risk()) * self.LIMIT_ORDER_ATTENUATION) - return self._check_factor(self.BUY_LIMIT_ORDER_MIN_PERCENT, - self.BUY_LIMIT_ORDER_MAX_PERCENT, - factor) - - """ - Starting point : self.STOP_LOSS_ORDER_MAX_PERCENT - trader.get_risk() --> low risk : stop level close to the current price - self.STOP_LOSS_ORDER_ATTENUATION --> try to contains the result between self.STOP_LOSS_ORDER_MIN_PERCENT and self.STOP_LOSS_ORDER_MAX_PERCENT - """ - - def _get_stop_price_from_risk(self, trader): - factor = self.STOP_LOSS_ORDER_MAX_PERCENT - (trader.get_risk() * self.STOP_LOSS_ORDER_ATTENUATION) - return self._check_factor(self.STOP_LOSS_ORDER_MIN_PERCENT, - self.STOP_LOSS_ORDER_MAX_PERCENT, - factor) - - """ - Starting point : self.QUANTITY_MIN_PERCENT - abs(eval_note) --> confirmation level --> high : sell/buy more quantity - trader.get_risk() --> high risk : sell / buy more quantity - abs(eval_note) + trader.get_risk() --> result between 0 and 2 --> self.MAX_SUM_RESULT - self.QUANTITY_ATTENUATION --> try to contains the result between self.QUANTITY_MIN_PERCENT and self.QUANTITY_MAX_PERCENT - """ - - def _get_limit_quantity_from_risk(self, eval_note, trader, quantity): - factor = self.QUANTITY_MIN_PERCENT + ((abs(eval_note) + trader.get_risk()) * self.QUANTITY_ATTENUATION) - return self._check_factor(self.QUANTITY_MIN_PERCENT, - self.QUANTITY_MAX_PERCENT, - factor) * quantity - - """ - Starting point : self.QUANTITY_MARKET_MIN_PERCENT - abs(eval_note) --> confirmation level --> high : sell/buy more quantity - trader.get_risk() --> high risk : sell / buy more quantity - abs(eval_note) + trader.get_risk() --> result between 0 and 2 --> self.MAX_SUM_RESULT - self.QUANTITY_MARKET_ATTENUATION --> try to contains the result between self.QUANTITY_MARKET_MIN_PERCENT and self.QUANTITY_MARKET_MAX_PERCENT - """ - - def _get_market_quantity_from_risk(self, eval_note, trader, quantity, buy=False): - factor = self.QUANTITY_MARKET_MIN_PERCENT + ( - (abs(eval_note) + trader.get_risk()) * self.QUANTITY_MARKET_ATTENUATION) - - # if buy market --> limit market usacge - if buy: - factor *= self.QUANTITY_BUY_MARKET_ATTENUATION - - return self._check_factor(self.QUANTITY_MARKET_MIN_PERCENT, - self.QUANTITY_MARKET_MAX_PERCENT, - factor) * quantity - - # creates a new order (or multiple split orders), always check EvaluatorOrderCreator.can_create_order() first. - def create_new_order(self, eval_note, symbol, exchange, trader, portfolio, state): - try: - last_prices = exchange.get_recent_trades(symbol) - reference_sum = 0 - - for last_price in last_prices[-ORDER_CREATION_LAST_TRADES_TO_USE:]: - reference_sum += float(last_price["price"]) - - reference = reference_sum / ORDER_CREATION_LAST_TRADES_TO_USE - - currency, market = split_symbol(symbol) - - current_portfolio = portfolio.get_currency_portfolio(currency) - current_market_quantity = portfolio.get_currency_portfolio(market) - - market_quantity = current_market_quantity / reference - - price = reference - symbol_market = exchange.get_market_status(symbol) - - created_orders = [] - - if state == EvaluatorStates.VERY_SHORT: - quantity = self._get_market_quantity_from_risk(eval_note, - trader, - current_portfolio) - for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, price, - symbol_market): - market = trader.create_order_instance(order_type=TraderOrderType.SELL_MARKET, - symbol=symbol, - current_price=order_price, - quantity=order_quantity, - price=order_price) - trader.create_order(market, portfolio) - created_orders.append(market) - return created_orders - - elif state == EvaluatorStates.SHORT: - quantity = self._get_limit_quantity_from_risk(eval_note, - trader, - current_portfolio) - limit_price = self._adapt_price(symbol_market, price * self._get_limit_price_from_risk(eval_note, trader)) - stop_price = self._adapt_price(symbol_market, price * self._get_stop_price_from_risk(trader)) - for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, - limit_price, - symbol_market): - limit = trader.create_order_instance(order_type=TraderOrderType.SELL_LIMIT, - symbol=symbol, - current_price=price, - quantity=order_quantity, - price=order_price) - updated_limit = trader.create_order(limit, portfolio) - created_orders.append(updated_limit) - - stop = trader.create_order_instance(order_type=TraderOrderType.STOP_LOSS, - symbol=symbol, - current_price=price, - quantity=order_quantity, - price=stop_price, - linked_to=updated_limit) - trader.create_order(stop, portfolio) - return created_orders - - elif state == EvaluatorStates.NEUTRAL: - pass - - # TODO : stop loss - elif state == EvaluatorStates.LONG: - quantity = self._get_limit_quantity_from_risk(eval_note, - trader, - market_quantity) - limit_price = self._adapt_price(symbol_market, price * self._get_limit_price_from_risk(eval_note, trader)) - for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, - limit_price, - symbol_market): - limit = trader.create_order_instance(order_type=TraderOrderType.BUY_LIMIT, - symbol=symbol, - current_price=price, - quantity=order_quantity, - price=order_price) - trader.create_order(limit, portfolio) - created_orders.append(limit) - return created_orders - - elif state == EvaluatorStates.VERY_LONG: - quantity = self._get_market_quantity_from_risk(eval_note, - trader, - market_quantity, - True) - for order_quantity, order_price in self._check_and_adapt_order_details_if_necessary(quantity, price, - symbol_market): - market = trader.create_order_instance(order_type=TraderOrderType.BUY_MARKET, - symbol=symbol, - current_price=order_price, - quantity=order_quantity, - price=order_price) - trader.create_order(market, portfolio) - created_orders.append(market) - return created_orders - - # if nothing go returned, return None - return None - - except Exception as e: - logging.getLogger(self.__class__.__name__).error("Failed to create order : {0}".format(e)) - return None - - -class DailyTradingModeDecider(AbstractTradingModeDecider): - def __init__(self, trading_mode, symbol_evaluator, exchange, symbol): - super().__init__(trading_mode, symbol_evaluator, exchange, symbol) - - def _set_final_eval(self): - strategies_analysis_note_counter = 0 - # Strategies analysis - for evaluated_strategies in self.symbol_evaluator.get_strategies_eval_list(self.exchange): - strategy_eval = evaluated_strategies.get_eval_note() - if check_valid_eval_note(strategy_eval): - self.final_eval += strategy_eval * evaluated_strategies.get_pertinence() - strategies_analysis_note_counter += evaluated_strategies.get_pertinence() - - if strategies_analysis_note_counter > 0: - self.final_eval /= strategies_analysis_note_counter - else: - self.final_eval = INIT_EVAL_NOTE - - def _get_delta_risk(self): - return self.RISK_THRESHOLD * self.symbol_evaluator.get_trader(self.exchange).get_risk() - - def _create_state(self): - delta_risk = self._get_delta_risk() - - if self.final_eval < self.VERY_LONG_THRESHOLD + delta_risk: - self._set_state(EvaluatorStates.VERY_LONG) - - elif self.final_eval < self.LONG_THRESHOLD + delta_risk: - self._set_state(EvaluatorStates.LONG) - - elif self.final_eval < self.NEUTRAL_THRESHOLD - delta_risk: - self._set_state(EvaluatorStates.NEUTRAL) - - elif self.final_eval < self.SHORT_THRESHOLD - delta_risk: - self._set_state(EvaluatorStates.SHORT) - - else: - self._set_state(EvaluatorStates.VERY_SHORT) - - def _set_state(self, new_state): - if new_state != self.state: - # previous_state = self.state - self.state = new_state - self.logger.info("{0} ** NEW FINAL STATE ** : {1}".format(self.symbol, self.state)) - - # if new state is not neutral --> cancel orders and create new else keep orders - if new_state is not EvaluatorStates.NEUTRAL: - - # cancel open orders - if self.symbol_evaluator.get_trader(self.exchange).is_enabled(): - self.symbol_evaluator.get_trader(self.exchange).cancel_open_orders(self.symbol) - if self.symbol_evaluator.get_trader_simulator(self.exchange).is_enabled(): - self.symbol_evaluator.get_trader_simulator(self.exchange).cancel_open_orders(self.symbol) - - # create notification - evaluator_notification = None - if self.notifier.enabled(): - evaluator_notification = self.notifier.notify_state_changed( - self.final_eval, - self.symbol_evaluator.get_crypto_currency_evaluator(), - self.symbol_evaluator.get_symbol(), - self.symbol_evaluator.get_trader(self.exchange), - self.state, - self.symbol_evaluator.get_matrix(self.exchange).get_matrix()) - - # call orders creation method - self.create_final_state_orders(evaluator_notification) diff --git a/trading/trader/modes/Default/high_frequency_mode.py b/trading/trader/modes/Default/high_frequency_mode.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/trading/trader/modes/Default/investor_mode.py b/trading/trader/modes/Default/investor_mode.py deleted file mode 100644 index 36b1408d4..000000000 --- a/trading/trader/modes/Default/investor_mode.py +++ /dev/null @@ -1,21 +0,0 @@ -from trading.trader.modes.abstract_mode_creator import AbstractTradingModeCreator -from trading.trader.modes.abstract_mode_decider import AbstractTradingModeDecider -from trading.trader.modes.abstract_trading_mode import AbstractTradingMode - - -class InvestorMode(AbstractTradingMode): - def __init__(self, config, symbol_evaluator, exchange, symbol): - super().__init__(config) - - self.set_creator(InvestorModeCreator(self)) - self.set_decider(InvestorModeDecider(self, symbol_evaluator, exchange, symbol)) - - -class InvestorModeCreator(AbstractTradingModeCreator): - def __init__(self, trading_mode): - super().__init__(trading_mode) - - -class InvestorModeDecider(AbstractTradingModeDecider): - def __init__(self, trading_mode, symbol_evaluator, exchange, symbol): - super().__init__(trading_mode, symbol_evaluator, exchange, symbol) diff --git a/trading/trader/modes/Default/objective_mode.py b/trading/trader/modes/Default/objective_mode.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/trading/trader/modes/Default/opportunity_mode.py b/trading/trader/modes/Default/opportunity_mode.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/trading/trader/modes/Default/safe_profit_mode.py b/trading/trader/modes/Default/safe_profit_mode.py deleted file mode 100644 index e69de29bb..000000000 From e1eab862b59bdb2a2781d1e459dc8f5bb21ec8ec Mon Sep 17 00:00:00 2001 From: Paul Bouquet Date: Sun, 3 Jun 2018 12:07:46 +0200 Subject: [PATCH 10/15] Update tentacle manager to perform trading mode installation --- config/cst.py | 10 ++++- tools/tentacle_manager.py | 82 ++++++++++++++++++++++++++------------- 2 files changed, 63 insertions(+), 29 deletions(-) diff --git a/config/cst.py b/config/cst.py index 5d513edab..84187f11f 100644 --- a/config/cst.py +++ b/config/cst.py @@ -148,6 +148,15 @@ TENTACLE_DESCRIPTION_LOCALISATION = "localisation" TENTACLE_DESCRIPTION_IS_URL = "is_url" +TENTACLE_TYPES = {"Evaluator": "evaluator", + "Social": "Social", + "RealTime": "RealTime", + "Util": "Util", + "TA": "TA", + "Strategies": "Strategies", + "Trading": "trading", + "Mode": "trader/modes"} + class EvaluatorMatrixTypes(Enum): TA = "TA" @@ -206,7 +215,6 @@ class TimeFrames(Enum): MIN_EVAL_TIME_FRAME = TimeFrames.FIVE_MINUTES - TimeFramesMinutes = { TimeFrames.ONE_MINUTE: 1, TimeFrames.THREE_MINUTES: 3, diff --git a/tools/tentacle_manager.py b/tools/tentacle_manager.py index 367ddd8bd..7c1ff4d9c 100644 --- a/tools/tentacle_manager.py +++ b/tools/tentacle_manager.py @@ -4,9 +4,10 @@ import requests -from config.cst import TENTACLES_PUBLIC_LIST, TENTACLES_DEFAULT_BRANCH, TENTACLES_PUBLIC_REPOSITORY, TENTACLE_DESCRIPTION,\ +from config.cst import TENTACLES_PUBLIC_LIST, TENTACLES_DEFAULT_BRANCH, TENTACLES_PUBLIC_REPOSITORY, \ + TENTACLE_DESCRIPTION, \ GITHUB_RAW_CONTENT_URL, CONFIG_EVALUATOR, EVALUATOR_DEFAULT_FOLDER, CONFIG_TENTACLES_KEY, GITHUB_BASE_URL, GITHUB, \ - TENTACLE_DESCRIPTION_LOCALISATION, TENTACLE_DESCRIPTION_IS_URL, EVALUATOR_ADVANCED_FOLDER + TENTACLE_DESCRIPTION_LOCALISATION, TENTACLE_DESCRIPTION_IS_URL, EVALUATOR_ADVANCED_FOLDER, TENTACLE_TYPES class TentacleManager: @@ -52,7 +53,7 @@ def _get_package_description(url_or_path, try_to_adapt=False): package_url_or_path = str(url_or_path) # if its an url: download with requests.get and return text if package_url_or_path.startswith("https://") \ - or package_url_or_path.startswith("http://") \ + or package_url_or_path.startswith("http://") \ or package_url_or_path.startswith("ftp://"): if try_to_adapt: if not package_url_or_path.endswith("/"): @@ -92,34 +93,59 @@ def _get_package_from_url(url): return package_file - def _apply_module(self, module_type, module_name, module_version, module_file, target_folder): - file_dir = "{0}/{1}/{2}".format(CONFIG_EVALUATOR, module_type, target_folder) + def _apply_module(self, module_type, module_subtype, module_version, module_file, target_folder, module_name): + if module_subtype in TENTACLE_TYPES and (module_subtype or module_subtype in TENTACLE_TYPES): + # create path from types + if module_subtype: + file_dir = "{0}/{1}/{2}".format(TENTACLE_TYPES[module_type], + TENTACLE_TYPES[module_subtype], + target_folder) + else: + file_dir = "{0}/{1}".format(TENTACLE_TYPES[module_type], + target_folder) + + # Install package in evaluator + with open("{0}/{1}.py".format(file_dir, module_name), "w") as installed_package: + installed_package.write(module_file) + + # Update local __init__ + new_line_in_init = "from .{0} import *\n".format(module_name) + init_content = "" + init_file = "{0}/{1}/{2}/__init__.py".format(TENTACLE_TYPES[module_type], + TENTACLE_TYPES[module_subtype], + target_folder) + + if os.path.isfile(init_file): + with open(init_file, "r") as init_file_r: + init_content = init_file_r.read() + + # check if line already exists + if init_content.find(new_line_in_init) == -1: + with open(init_file, "w") as init_file_w: + # add new package to init + init_file_w.write(init_content + new_line_in_init) + + self.logger.info("{0} {1} successfully installed in: {2}" + .format(module_name, module_version, file_dir)) - # Install package in evaluator - with open("{0}/{1}.py".format(file_dir, module_name), "w") as installed_package: - installed_package.write(module_file) - - # Update local __init__ - new_line_in_init = "from .{0} import *\n".format(module_name) - init_content = "" - init_file = "{0}/{1}/{2}/__init__.py".format(CONFIG_EVALUATOR, module_type, target_folder) - - if os.path.isfile(init_file): - with open(init_file, "r") as init_file_r: - init_content = init_file_r.read() - - # check if line already exists - if init_content.find(new_line_in_init) == -1: - with open(init_file, "w") as init_file_w: - # add new package to init - init_file_w.write(init_content + new_line_in_init) - - self.logger.info("{0} {1} successfully installed in: {2}" - .format(module_name, module_version, file_dir)) + else: + raise Exception("Tentacle type not found") def install_module(self, package, module_name, package_localisation, is_url, target_folder): package_type = package[module_name]["type"] - module_loc = "{0}/{1}/{2}.py".format(package_localisation, package_type, module_name) + package_subtype = package[module_name]["subtype"] + + # create path from types + if package_subtype: + module_loc = "{0}/{1}/{2}/{3}.py".format(package_localisation, + package_type, + package_subtype, + module_name) + else: + module_loc = "{0}/{1}/{2}.py".format(package_localisation, + package_type, + module_name) + module_version = package[module_name]["version"] if is_url: @@ -128,7 +154,7 @@ def install_module(self, package, module_name, package_localisation, is_url, tar with open(module_loc, "r") as module: module_file = module.read() - self._apply_module(package_type, module_name, module_version, module_file, target_folder) + self._apply_module(package_type, package_subtype, module_version, module_file, target_folder, module_name) def _try_to_install_package(self, package, target_folder): package_description = package[TENTACLE_DESCRIPTION] From 33f60b22d9bd6e591feb7d29bd65399ca28a99af Mon Sep 17 00:00:00 2001 From: Paul Bouquet Date: Sun, 3 Jun 2018 12:29:58 +0200 Subject: [PATCH 11/15] Fix tests --- evaluator/symbol_evaluator.py | 2 - tests/static/config.json | 3 +- ....py => test_daily_trading_mode_creator.py} | 84 ++++++++++++------- ....py => test_daily_trading_mode_decider.py} | 7 +- 4 files changed, 62 insertions(+), 34 deletions(-) rename tests/unit_tests/trading_modes_tests/{test_mode_creator.py => test_daily_trading_mode_creator.py} (84%) rename tests/unit_tests/trading_modes_tests/{test_mode_decider.py => test_daily_trading_mode_decider.py} (95%) diff --git a/evaluator/symbol_evaluator.py b/evaluator/symbol_evaluator.py index e6c919407..b7b9d997c 100644 --- a/evaluator/symbol_evaluator.py +++ b/evaluator/symbol_evaluator.py @@ -43,8 +43,6 @@ def add_evaluator_thread_manager(self, exchange, symbol, time_frame, evaluator_t self.evaluator_thread_managers[exchange.get_name()][time_frame] = evaluator_thread else: self.evaluator_thread_managers[exchange.get_name()] = {time_frame: evaluator_thread} - - # TODO use config self.trading_mode_instances[exchange.get_name()] = self.trading_mode_class(self.config, self, exchange, symbol) diff --git a/tests/static/config.json b/tests/static/config.json index a7e1d8087..4b7f0ae34 100644 --- a/tests/static/config.json +++ b/tests/static/config.json @@ -42,7 +42,8 @@ }, "trader":{ "enabled": false, - "risk": 1 + "risk": 1, + "mode": "DailyTradingMode" }, "trader_simulator":{ "enabled": true, diff --git a/tests/unit_tests/trading_modes_tests/test_mode_creator.py b/tests/unit_tests/trading_modes_tests/test_daily_trading_mode_creator.py similarity index 84% rename from tests/unit_tests/trading_modes_tests/test_mode_creator.py rename to tests/unit_tests/trading_modes_tests/test_daily_trading_mode_creator.py index e278fdf0a..e9079468e 100644 --- a/tests/unit_tests/trading_modes_tests/test_mode_creator.py +++ b/tests/unit_tests/trading_modes_tests/test_daily_trading_mode_creator.py @@ -1,10 +1,10 @@ import ccxt import copy -from trading.trader.modes.abstract_mode_creator import AbstractTradingModeCreator from trading.exchanges.exchange_manager import ExchangeManager from config.cst import EvaluatorStates from tests.test_utils.config import load_test_config +from trading.trader.modes import DailyTradingModeCreator from trading.trader.portfolio import Portfolio from trading.trader.order import * from trading.trader.trader_simulator import TraderSimulator @@ -43,31 +43,44 @@ def test_can_create_order(): min_trigger_market = "ADA/BNB" # order from neutral state => false - assert not AbstractTradingModeCreator.can_create_order(symbol, exchange, EvaluatorStates.NEUTRAL, portfolio) + assert not DailyTradingModeCreator(None).can_create_order(symbol, exchange, + EvaluatorStates.NEUTRAL, portfolio) # sell order using a currency with 0 available - assert not AbstractTradingModeCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.SHORT, portfolio) - assert not AbstractTradingModeCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.VERY_SHORT, portfolio) + assert not DailyTradingModeCreator(None).can_create_order(not_owned_symbol, exchange, + EvaluatorStates.SHORT, portfolio) + assert not DailyTradingModeCreator(None).can_create_order(not_owned_symbol, exchange, + EvaluatorStates.VERY_SHORT, portfolio) # sell order using a currency with < min available - assert not AbstractTradingModeCreator.can_create_order(min_trigger_symbol, exchange, EvaluatorStates.SHORT, portfolio) - assert not AbstractTradingModeCreator.can_create_order(min_trigger_symbol, exchange, EvaluatorStates.VERY_SHORT, portfolio) + assert not DailyTradingModeCreator(None).can_create_order(min_trigger_symbol, exchange, + EvaluatorStates.SHORT, portfolio) + assert not DailyTradingModeCreator(None).can_create_order(min_trigger_symbol, exchange, + EvaluatorStates.VERY_SHORT, portfolio) # sell order using a currency with > min available - assert AbstractTradingModeCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.SHORT, portfolio) - assert AbstractTradingModeCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.VERY_SHORT, portfolio) + assert DailyTradingModeCreator(None).can_create_order(not_owned_market, exchange, + EvaluatorStates.SHORT, portfolio) + assert DailyTradingModeCreator(None).can_create_order(not_owned_market, exchange, + EvaluatorStates.VERY_SHORT, portfolio) # buy order using a market with 0 available - assert not AbstractTradingModeCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.LONG, portfolio) - assert not AbstractTradingModeCreator.can_create_order(not_owned_market, exchange, EvaluatorStates.VERY_LONG, portfolio) + assert not DailyTradingModeCreator(None).can_create_order(not_owned_market, exchange, + EvaluatorStates.LONG, portfolio) + assert not DailyTradingModeCreator(None).can_create_order(not_owned_market, exchange, + EvaluatorStates.VERY_LONG, portfolio) # buy order using a market with < min available - assert not AbstractTradingModeCreator.can_create_order(min_trigger_market, exchange, EvaluatorStates.LONG, portfolio) - assert not AbstractTradingModeCreator.can_create_order(min_trigger_market, exchange, EvaluatorStates.VERY_LONG, portfolio) + assert not DailyTradingModeCreator(None).can_create_order(min_trigger_market, exchange, + EvaluatorStates.LONG, portfolio) + assert not DailyTradingModeCreator(None).can_create_order(min_trigger_market, exchange, + EvaluatorStates.VERY_LONG, portfolio) # buy order using a market with > min available - assert AbstractTradingModeCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.LONG, portfolio) - assert AbstractTradingModeCreator.can_create_order(not_owned_symbol, exchange, EvaluatorStates.VERY_LONG, portfolio) + assert DailyTradingModeCreator(None).can_create_order(not_owned_symbol, exchange, + EvaluatorStates.LONG, portfolio) + assert DailyTradingModeCreator(None).can_create_order(not_owned_symbol, exchange, + EvaluatorStates.VERY_LONG, portfolio) def test_can_create_order_unknown_symbols(): @@ -78,21 +91,32 @@ def test_can_create_order_unknown_symbols(): unknown_everything = "VI?/*s?" # buy order with unknown market - assert not AbstractTradingModeCreator.can_create_order(unknown_market, exchange, EvaluatorStates.LONG, portfolio) - assert not AbstractTradingModeCreator.can_create_order(unknown_market, exchange, EvaluatorStates.VERY_LONG, portfolio) - assert AbstractTradingModeCreator.can_create_order(unknown_market, exchange, EvaluatorStates.SHORT, portfolio) - assert AbstractTradingModeCreator.can_create_order(unknown_market, exchange, EvaluatorStates.VERY_SHORT, portfolio) + assert not DailyTradingModeCreator(None).can_create_order(unknown_market, exchange, + EvaluatorStates.LONG, portfolio) + assert not DailyTradingModeCreator(None).can_create_order(unknown_market, exchange, + EvaluatorStates.VERY_LONG, portfolio) + assert DailyTradingModeCreator(None).can_create_order(unknown_market, exchange, + EvaluatorStates.SHORT, portfolio) + assert DailyTradingModeCreator(None).can_create_order(unknown_market, exchange, + EvaluatorStates.VERY_SHORT, portfolio) # sell order with unknown symbol - assert not AbstractTradingModeCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.SHORT, portfolio) - assert not AbstractTradingModeCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.VERY_SHORT, portfolio) - assert AbstractTradingModeCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.LONG, portfolio) - assert AbstractTradingModeCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.VERY_LONG, portfolio) + assert not DailyTradingModeCreator(None).can_create_order(unknown_symbol, exchange, + EvaluatorStates.SHORT, portfolio) + assert not DailyTradingModeCreator(None).can_create_order(unknown_symbol, exchange, + EvaluatorStates.VERY_SHORT, portfolio) + assert DailyTradingModeCreator(None).can_create_order(unknown_symbol, exchange, + EvaluatorStates.LONG, portfolio) + assert DailyTradingModeCreator(None).can_create_order(unknown_symbol, exchange, + EvaluatorStates.VERY_LONG, portfolio) # neutral state with unknown symbol, market and everything - assert not AbstractTradingModeCreator.can_create_order(unknown_symbol, exchange, EvaluatorStates.NEUTRAL, portfolio) - assert not AbstractTradingModeCreator.can_create_order(unknown_market, exchange, EvaluatorStates.NEUTRAL, portfolio) - assert not AbstractTradingModeCreator.can_create_order(unknown_everything, exchange, EvaluatorStates.NEUTRAL, portfolio) + assert not DailyTradingModeCreator(None).can_create_order(unknown_symbol, exchange, + EvaluatorStates.NEUTRAL, portfolio) + assert not DailyTradingModeCreator(None).can_create_order(unknown_market, exchange, + EvaluatorStates.NEUTRAL, portfolio) + assert not DailyTradingModeCreator(None).can_create_order(unknown_everything, exchange, + EvaluatorStates.NEUTRAL, portfolio) def _check_order_limits(order, market_status): @@ -144,7 +168,7 @@ def _check_linked_order(order, linked_order, order_type, order_price, market_sta def test_valid_create_new_order(): config, exchange, trader, symbol = _get_tools() portfolio = trader.get_portfolio() - order_creator = AbstractTradingModeCreator() + order_creator = DailyTradingModeCreator(None) market_status = exchange.get_market_status(symbol) @@ -263,7 +287,7 @@ def test_valid_create_new_order(): def test_invalid_create_new_order(): config, exchange, trader, symbol = _get_tools() portfolio = trader.get_portfolio() - order_creator = AbstractTradingModeCreator() + order_creator = DailyTradingModeCreator(None) # portfolio: "BTC": 10 "USD": 1000 min_trigger_market = "ADA/BNB" @@ -294,7 +318,7 @@ def test_invalid_create_new_order(): def test_split_create_new_order(): config, exchange, trader, symbol = _get_tools() portfolio = trader.get_portfolio() - order_creator = AbstractTradingModeCreator() + order_creator = DailyTradingModeCreator(None) last_btc_price = 6943.01 market_status = exchange.get_market_status(symbol) @@ -513,7 +537,7 @@ def _check_portfolio(portfolio, initial_portfolio, orders, only_positivity=False def test_create_order_using_a_lot_of_different_inputs_with_portfolio_reset(): config, exchange, trader, symbol = _get_tools() portfolio = trader.get_portfolio() - order_creator = AbstractTradingModeCreator() + order_creator = DailyTradingModeCreator(None) gradient_step = 0.001 nb_orders = 1 market_status = exchange.get_market_status(symbol) @@ -569,7 +593,7 @@ def _fill_orders(orders, trader): def test_create_order_using_a_lot_of_different_inputs_without_portfolio_reset(): config, exchange, trader, symbol = _get_tools() portfolio = trader.get_portfolio() - order_creator = AbstractTradingModeCreator() + order_creator = DailyTradingModeCreator(None) gradient_step = 0.001 nb_orders = "unknown" market_status = exchange.get_market_status(symbol) diff --git a/tests/unit_tests/trading_modes_tests/test_mode_decider.py b/tests/unit_tests/trading_modes_tests/test_daily_trading_mode_decider.py similarity index 95% rename from tests/unit_tests/trading_modes_tests/test_mode_decider.py rename to tests/unit_tests/trading_modes_tests/test_daily_trading_mode_decider.py index bb8badcc2..af507e7d5 100644 --- a/tests/unit_tests/trading_modes_tests/test_mode_decider.py +++ b/tests/unit_tests/trading_modes_tests/test_daily_trading_mode_decider.py @@ -2,6 +2,7 @@ from trading.exchanges.exchange_manager import ExchangeManager from evaluator.symbol_evaluator import SymbolEvaluator +from trading.trader.modes import DailyTradingModeDecider, DailyTradingMode from trading.trader.trader_simulator import TraderSimulator from evaluator.cryptocurrency_evaluator import CryptocurrencyEvaluator from trading.trader.modes.abstract_mode_decider import AbstractTradingModeDecider @@ -31,7 +32,11 @@ def _get_tools(): symbol_evaluator.set_trader_simulators(exchange_traders) symbol_evaluator.set_traders(exchange_traders2) symbol_evaluator.strategies_eval_lists[exchange_inst.get_name()] = EvaluatorCreator.create_strategies_eval_list(config) - final_evaluator = AbstractTradingModeDecider(symbol_evaluator, exchange_inst, symbol) + + trading_mode = DailyTradingMode(config, symbol_evaluator, exchange_inst, symbol) + final_evaluator = trading_mode.get_decider() + symbol_evaluator.trading_mode_instances[exchange_inst.get_name()] = trading_mode + trader_inst.portfolio.portfolio["USDT"] = { Portfolio.TOTAL: 2000, Portfolio.AVAILABLE: 2000 From 1eb5615acd767406357ef18434e748c7e3bbd607 Mon Sep 17 00:00:00 2001 From: Guillaume De Saint Martin Date: Sun, 3 Jun 2018 22:10:46 +0200 Subject: [PATCH 12/15] added Default and Advanced folders for trading modes --- trading/trader/modes/Advanced/.keep | 0 trading/trader/modes/Default/.keep | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 trading/trader/modes/Advanced/.keep create mode 100644 trading/trader/modes/Default/.keep diff --git a/trading/trader/modes/Advanced/.keep b/trading/trader/modes/Advanced/.keep new file mode 100644 index 000000000..e69de29bb diff --git a/trading/trader/modes/Default/.keep b/trading/trader/modes/Default/.keep new file mode 100644 index 000000000..e69de29bb From 271f34f1e87ad5cd2479405769078b85cbcbc365 Mon Sep 17 00:00:00 2001 From: Guillaume De Saint Martin Date: Sun, 3 Jun 2018 22:55:02 +0200 Subject: [PATCH 13/15] adapted protected methods names --- .../test_daily_trading_mode_decider.py | 4 +- trading/trader/modes/abstract_mode_creator.py | 114 ++++++++---------- trading/trader/modes/abstract_mode_decider.py | 58 ++++----- 3 files changed, 77 insertions(+), 99 deletions(-) diff --git a/tests/unit_tests/trading_modes_tests/test_daily_trading_mode_decider.py b/tests/unit_tests/trading_modes_tests/test_daily_trading_mode_decider.py index af507e7d5..3989030f2 100644 --- a/tests/unit_tests/trading_modes_tests/test_daily_trading_mode_decider.py +++ b/tests/unit_tests/trading_modes_tests/test_daily_trading_mode_decider.py @@ -90,7 +90,7 @@ def test_create_state(): delta_risk = final_evaluator._get_delta_risk() for i in range(-100, 100, 1): final_evaluator.final_eval = i/100 - final_evaluator._create_state() + final_evaluator.create_state() if final_evaluator.final_eval < final_evaluator.VERY_LONG_THRESHOLD + delta_risk: assert final_evaluator.state == EvaluatorStates.VERY_LONG elif final_evaluator.final_eval < final_evaluator.LONG_THRESHOLD + delta_risk: @@ -109,7 +109,7 @@ def test_prepare(): assert final_evaluator.state == EvaluatorStates.SHORT assert len(trader_inst.order_manager.order_list) == 2 # has stop loss final_evaluator.final_eval = None - final_evaluator._set_final_eval() + final_evaluator.set_final_eval() assert final_evaluator.state == EvaluatorStates.SHORT # ensure did not change EvaluatorStates assert len(trader_inst.order_manager.order_list) == 2 # ensure did not change orders assert final_evaluator.final_eval == INIT_EVAL_NOTE diff --git a/trading/trader/modes/abstract_mode_creator.py b/trading/trader/modes/abstract_mode_creator.py index 5664144c7..0ac30290d 100644 --- a/trading/trader/modes/abstract_mode_creator.py +++ b/trading/trader/modes/abstract_mode_creator.py @@ -35,7 +35,7 @@ def __init__(self, trading_mode): / self.MAX_SUM_RESULT @staticmethod - def _check_factor(min_val, max_val, factor): + def check_factor(min_val, max_val, factor): if factor > max_val: return max_val elif factor < min_val: @@ -44,60 +44,12 @@ def _check_factor(min_val, max_val, factor): return factor @staticmethod - def _trunc_with_n_decimal_digits(value, digits): - # force exact representation - return float("{0:.{1}f}".format(math.trunc(value*10**digits)/(10**digits), digits)) - - @staticmethod - def _get_value_or_default(dictionary, key, default=math.nan): - if key in dictionary: - value = dictionary[key] - return value if value is not None else default - return default - - @staticmethod - def _adapt_order_quantity_because_quantity(limiting_value, max_value, quantity_to_adapt, price, symbol_market): - orders = [] - nb_full_orders = limiting_value // max_value - rest_order_quantity = limiting_value % max_value - after_rest_quantity_to_adapt = quantity_to_adapt - if rest_order_quantity > 0: - after_rest_quantity_to_adapt -= rest_order_quantity - valid_last_order_quantity = AbstractTradingModeCreator._adapt_quantity(symbol_market, rest_order_quantity) - orders.append((valid_last_order_quantity, price)) - - other_orders_quantity = (after_rest_quantity_to_adapt + max_value)/(nb_full_orders+1) - valid_other_orders_quantity = AbstractTradingModeCreator._adapt_quantity(symbol_market, other_orders_quantity) - orders += [(valid_other_orders_quantity, price)]*int(nb_full_orders) - return orders - - @staticmethod - def _adapt_order_quantity_because_price(limiting_value, max_value, price, symbol_market): - orders = [] - nb_full_orders = limiting_value // max_value - rest_order_cost = limiting_value % max_value - if rest_order_cost > 0: - valid_last_order_quantity = AbstractTradingModeCreator._adapt_quantity(symbol_market, rest_order_cost / price) - orders.append((valid_last_order_quantity, price)) - - other_orders_quantity = max_value / price - valid_other_orders_quantity = AbstractTradingModeCreator._adapt_quantity(symbol_market, other_orders_quantity) - orders += [(valid_other_orders_quantity, price)] * int(nb_full_orders) - return orders - - @staticmethod - def _adapt_price(symbol_market, price): + def adapt_price(symbol_market, price): maximal_price_digits = AbstractTradingModeCreator._get_value_or_default(symbol_market[Ecmsc.PRECISION.value], Ecmsc.PRECISION_PRICE.value, CURRENCY_DEFAULT_MAX_PRICE_DIGITS) return AbstractTradingModeCreator._trunc_with_n_decimal_digits(price, maximal_price_digits) - @staticmethod - def _adapt_quantity(symbol_market, quantity): - maximal_volume_digits = AbstractTradingModeCreator._get_value_or_default(symbol_market[Ecmsc.PRECISION.value], - Ecmsc.PRECISION_AMOUNT.value, 0) - return AbstractTradingModeCreator._trunc_with_n_decimal_digits(quantity, maximal_volume_digits) - """ Checks and adapts the quantity and price of the order to ensure it's exchange compliant: - are the quantity and price of the order compliant with the exchange's number of digits requirement @@ -112,7 +64,7 @@ def _adapt_quantity(symbol_market, quantity): """ @staticmethod - def _check_and_adapt_order_details_if_necessary(quantity, price, symbol_market): + def check_and_adapt_order_details_if_necessary(quantity, price, symbol_market): symbol_market_limits = symbol_market[Ecmsc.LIMITS.value] limit_amount = symbol_market_limits[Ecmsc.LIMITS_AMOUNT.value] @@ -128,7 +80,7 @@ def _check_and_adapt_order_details_if_necessary(quantity, price, symbol_market): # adapt digits if necessary valid_quantity = AbstractTradingModeCreator._adapt_quantity(symbol_market, quantity) - valid_price = AbstractTradingModeCreator._adapt_price(symbol_market, price) + valid_price = AbstractTradingModeCreator.adapt_price(symbol_market, price) total_order_price = valid_quantity * valid_price @@ -176,20 +128,52 @@ def can_create_order(symbol, exchange, state, portfolio): @abstractmethod def create_new_order(self, eval_note, symbol, exchange, trader, portfolio, state): - raise NotImplementedError("Create_new_order not implemented") + raise NotImplementedError("create_new_order not implemented") - @abstractmethod - def _get_limit_price_from_risk(self, eval_note, trader): - raise NotImplementedError("Set_final_eval not implemented") + @staticmethod + def _adapt_quantity(symbol_market, quantity): + maximal_volume_digits = AbstractTradingModeCreator._get_value_or_default(symbol_market[Ecmsc.PRECISION.value], + Ecmsc.PRECISION_AMOUNT.value, 0) + return AbstractTradingModeCreator._trunc_with_n_decimal_digits(quantity, maximal_volume_digits) - @abstractmethod - def _get_stop_price_from_risk(self, trader): - raise NotImplementedError("Set_final_eval not implemented") + @staticmethod + def _trunc_with_n_decimal_digits(value, digits): + # force exact representation + return float("{0:.{1}f}".format(math.trunc(value*10**digits)/(10**digits), digits)) - @abstractmethod - def _get_limit_quantity_from_risk(self, eval_note, trader, quantity): - raise NotImplementedError("Set_final_eval not implemented") + @staticmethod + def _get_value_or_default(dictionary, key, default=math.nan): + if key in dictionary: + value = dictionary[key] + return value if value is not None else default + return default - @abstractmethod - def _get_market_quantity_from_risk(self, eval_note, trader, quantity, buy=False): - raise NotImplementedError("Set_final_eval not implemented") + @staticmethod + def _adapt_order_quantity_because_quantity(limiting_value, max_value, quantity_to_adapt, price, symbol_market): + orders = [] + nb_full_orders = limiting_value // max_value + rest_order_quantity = limiting_value % max_value + after_rest_quantity_to_adapt = quantity_to_adapt + if rest_order_quantity > 0: + after_rest_quantity_to_adapt -= rest_order_quantity + valid_last_order_quantity = AbstractTradingModeCreator._adapt_quantity(symbol_market, rest_order_quantity) + orders.append((valid_last_order_quantity, price)) + + other_orders_quantity = (after_rest_quantity_to_adapt + max_value)/(nb_full_orders+1) + valid_other_orders_quantity = AbstractTradingModeCreator._adapt_quantity(symbol_market, other_orders_quantity) + orders += [(valid_other_orders_quantity, price)]*int(nb_full_orders) + return orders + + @staticmethod + def _adapt_order_quantity_because_price(limiting_value, max_value, price, symbol_market): + orders = [] + nb_full_orders = limiting_value // max_value + rest_order_cost = limiting_value % max_value + if rest_order_cost > 0: + valid_last_order_quantity = AbstractTradingModeCreator._adapt_quantity(symbol_market, rest_order_cost / price) + orders.append((valid_last_order_quantity, price)) + + other_orders_quantity = max_value / price + valid_other_orders_quantity = AbstractTradingModeCreator._adapt_quantity(symbol_market, other_orders_quantity) + orders += [(valid_other_orders_quantity, price)] * int(nb_full_orders) + return orders diff --git a/trading/trader/modes/abstract_mode_decider.py b/trading/trader/modes/abstract_mode_decider.py index 6897e7b65..c853af237 100644 --- a/trading/trader/modes/abstract_mode_decider.py +++ b/trading/trader/modes/abstract_mode_decider.py @@ -43,6 +43,32 @@ def create_final_state_orders(self, evaluator_notification): self._create_order_if_possible(evaluator_notification, self.symbol_evaluator.get_trader(self.exchange)) + def get_state(self): + return self.state + + def get_final_eval(self): + return self.final_eval + + def finalize(self): + # reset previous note + self.final_eval = INIT_EVAL_NOTE + + self.set_final_eval() + self.create_state() + + def stop(self): + self.keep_running = False + + # called first by finalize => when any notification appears + @abstractmethod + def set_final_eval(self): + raise NotImplementedError("_set_final_eval not implemented") + + # called after _set_final_eval by finalize => when any notification appears + @abstractmethod + def create_state(self): + raise NotImplementedError("_create_state not implemented") + # for each trader call the creator to check if order creation is possible and create it def _create_order_if_possible(self, evaluator_notification, trader): if trader.is_enabled(): @@ -63,35 +89,3 @@ def _push_order_notification_if_possible(order_list, notification): if order_list: for order in order_list: order.get_order_notifier().notify(notification) - - def get_state(self): - return self.state - - def get_final_eval(self): - return self.final_eval - - def finalize(self): - # reset previous note - self.final_eval = INIT_EVAL_NOTE - - self._set_final_eval() - self._create_state() - - def stop(self): - self.keep_running = False - - @abstractmethod - def _set_final_eval(self): - raise NotImplementedError("Set_final_eval not implemented") - - @abstractmethod - def _get_delta_risk(self): - raise NotImplementedError("Get_delta_risk not implemented") - - @abstractmethod - def _create_state(self): - raise NotImplementedError("Create_state not implemented") - - @abstractmethod - def _set_state(self, new_state): - raise NotImplementedError("Set_state not implemented") From e45ae5c11667c5d313b8daa9bb4002730e6b8ba5 Mon Sep 17 00:00:00 2001 From: Guillaume De Saint Martin Date: Sun, 3 Jun 2018 23:10:27 +0200 Subject: [PATCH 14/15] fixed symbol_evaluator test --- tests/unit_tests/evaluator_tests/test_symbol_evaluator.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unit_tests/evaluator_tests/test_symbol_evaluator.py b/tests/unit_tests/evaluator_tests/test_symbol_evaluator.py index f1b8b264f..4b5e6221f 100644 --- a/tests/unit_tests/evaluator_tests/test_symbol_evaluator.py +++ b/tests/unit_tests/evaluator_tests/test_symbol_evaluator.py @@ -47,5 +47,5 @@ def _get_tools(): def test_init(): symbol_evaluator, exchange_inst, time_frame, evaluator_thread_manager = _get_tools() - assert symbol_evaluator.evaluator_order_creator + assert symbol_evaluator.trading_mode_class assert symbol_evaluator.evaluator_thread_managers[exchange_inst.get_name()][time_frame] == evaluator_thread_manager From 2513ab4238545a690d279bcfd369953e9389c06c Mon Sep 17 00:00:00 2001 From: Paul Bouquet Date: Sun, 3 Jun 2018 23:12:50 +0200 Subject: [PATCH 15/15] #198 [Order Creation] Implement new architecture --- config/cst.py | 2 +- docs/CHANGELOG.md | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/config/cst.py b/config/cst.py index 84187f11f..1edae018a 100644 --- a/config/cst.py +++ b/config/cst.py @@ -1,7 +1,7 @@ from enum import Enum SHORT_VERSION = "0.1.0" -REV_VERSION = "1" +REV_VERSION = "2" VERSION_DEV_PHASE = "beta" VERSION = "{0}-{1}".format(SHORT_VERSION, VERSION_DEV_PHASE) LONG_VERSION = "{0}_{1}-{2}".format(SHORT_VERSION, REV_VERSION, VERSION_DEV_PHASE) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 146a73527..6d5ecade0 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,3 +1,16 @@ +Changelog for 0.1.0_2-beta +==================== +*Released date : June 3 2018* + +**Info** : +- Config : "mode" key added to "trader" + +# Concerned issues : + #198 [Order Creation] Implement new architecture + +# New features : + - Trading modes + Changelog for 0.1.0_1-beta ==================== *Released date : June 2 2018*