From f5a70750f0f19eb1867d52950c27971cf5caba91 Mon Sep 17 00:00:00 2001 From: misagh Date: Mon, 26 Nov 2018 21:06:32 +0100 Subject: [PATCH 01/31] edge real position sizing drafted --- freqtrade/edge/__init__.py | 16 +++++++++++++--- freqtrade/freqtradebot.py | 4 +++- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/freqtrade/edge/__init__.py b/freqtrade/edge/__init__.py index 009b80664..6be09b19d 100644 --- a/freqtrade/edge/__init__.py +++ b/freqtrade/edge/__init__.py @@ -9,6 +9,7 @@ import utils_find_1st as utf1st from pandas import DataFrame import freqtrade.optimize as optimize +from freqtrade import constants, OperationalException from freqtrade.arguments import Arguments from freqtrade.arguments import TimeRange from freqtrade.strategy.interface import SellType @@ -53,7 +54,15 @@ class Edge(): self.edge_config = self.config.get('edge', {}) self._cached_pairs: Dict[str, Any] = {} # Keeps a list of pairs - self._total_capital: float = self.config['stake_amount'] + # checking max_open_trades. it should be -1 as with Edge + # the number of trades is determined by position size + if self.config['max_open_trades'] != -1: + logger.critical('max_open_trades should be -1 in config !') + + if self.config['stake_amount'] != constants.UNLIMITED_STAKE_AMOUNT: + raise OperationalException('Edge works only with unlimited stake amount') + + self._capital_percentage: float = self.edge_config.get('capital_available_percentage') self._allowed_risk: float = self.edge_config.get('allowed_risk') self._since_number_of_days: int = self.edge_config.get('calculate_since_number_of_days', 14) self._last_updated: int = 0 # Timestamp of pairs last updated time @@ -150,9 +159,10 @@ class Edge(): return True - def stake_amount(self, pair: str) -> float: + def stake_amount(self, pair: str, capital: float) -> float: stoploss = self._cached_pairs[pair].stoploss - allowed_capital_at_risk = round(self._total_capital * self._allowed_risk, 5) + available_capital = capital * self._capital_percentage + allowed_capital_at_risk = round(available_capital * self._allowed_risk, 5) position_size = abs(round((allowed_capital_at_risk / stoploss), 5)) return position_size diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 602c4ae2f..a6d2df954 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -333,7 +333,9 @@ class FreqtradeBot(object): :return: float: Stake Amount """ if self.edge: - stake_amount = self.edge.stake_amount(pair) + stake_amount = self.edge.stake_amount( + pair, self.wallets.get_free(self.config['stake_currency']) + ) else: stake_amount = self.config['stake_amount'] From 159ac6e6573a9d44a244482739cf199eff1155d4 Mon Sep 17 00:00:00 2001 From: misagh Date: Tue, 27 Nov 2018 14:02:34 +0100 Subject: [PATCH 02/31] edge tests fixed for position sizing --- freqtrade/edge/__init__.py | 6 +++--- freqtrade/freqtradebot.py | 4 +--- freqtrade/tests/conftest.py | 4 ++++ freqtrade/tests/edge/test_edge.py | 20 ++++++++++---------- freqtrade/tests/test_freqtradebot.py | 4 ++-- 5 files changed, 20 insertions(+), 18 deletions(-) diff --git a/freqtrade/edge/__init__.py b/freqtrade/edge/__init__.py index 6be09b19d..f5961d9b4 100644 --- a/freqtrade/edge/__init__.py +++ b/freqtrade/edge/__init__.py @@ -162,8 +162,8 @@ class Edge(): def stake_amount(self, pair: str, capital: float) -> float: stoploss = self._cached_pairs[pair].stoploss available_capital = capital * self._capital_percentage - allowed_capital_at_risk = round(available_capital * self._allowed_risk, 5) - position_size = abs(round((allowed_capital_at_risk / stoploss), 5)) + allowed_capital_at_risk = round(available_capital * self._allowed_risk, 15) + position_size = abs(round((allowed_capital_at_risk / stoploss), 15)) return position_size def stoploss(self, pair: str) -> float: @@ -207,7 +207,7 @@ class Edge(): # 0.05% is 0.0005 # fee = 0.001 - stake = self.config.get('stake_amount') + stake = 0.015 fee = self.fee open_fee = fee / 2 diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index a6d2df954..937fa0d3f 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -336,6 +336,7 @@ class FreqtradeBot(object): stake_amount = self.edge.stake_amount( pair, self.wallets.get_free(self.config['stake_currency']) ) + return stake_amount else: stake_amount = self.config['stake_amount'] @@ -782,9 +783,6 @@ class FreqtradeBot(object): if sell_reason in (SellType.STOP_LOSS, SellType.TRAILING_STOP_LOSS): sell_type = 'stoploss' - if self.config.get('dry_run', False) and sell_type == 'stoploss': - limit = trade.stop_loss - # Execute sell and update trade record order_id = self.exchange.sell(pair=str(trade.pair), ordertype=self.strategy.order_types[sell_type], diff --git a/freqtrade/tests/conftest.py b/freqtrade/tests/conftest.py index f7fe697b8..75c8032f1 100644 --- a/freqtrade/tests/conftest.py +++ b/freqtrade/tests/conftest.py @@ -10,6 +10,7 @@ import arrow import pytest from telegram import Chat, Message, Update +from freqtrade import constants from freqtrade.exchange.exchange_helpers import parse_ticker_dataframe from freqtrade.exchange import Exchange from freqtrade.edge import Edge, PairInfo @@ -787,10 +788,13 @@ def buy_order_fee(): @pytest.fixture(scope="function") def edge_conf(default_conf): + default_conf['max_open_trades'] = -1 + default_conf['stake_amount'] = constants.UNLIMITED_STAKE_AMOUNT default_conf['edge'] = { "enabled": True, "process_throttle_secs": 1800, "calculate_since_number_of_days": 14, + "capital_available_percentage": 0.5, "allowed_risk": 0.01, "stoploss_range_min": -0.01, "stoploss_range_max": -0.1, diff --git a/freqtrade/tests/edge/test_edge.py b/freqtrade/tests/edge/test_edge.py index fac055c17..40bb35209 100644 --- a/freqtrade/tests/edge/test_edge.py +++ b/freqtrade/tests/edge/test_edge.py @@ -123,9 +123,9 @@ def test_edge_results(edge_conf, mocker, caplog, data) -> None: assert res.close_time == _get_frame_time_from_offset(trade.close_tick) -def test_adjust(mocker, default_conf): - freqtrade = get_patched_freqtradebot(mocker, default_conf) - edge = Edge(default_conf, freqtrade.exchange, freqtrade.strategy) +def test_adjust(mocker, edge_conf): + freqtrade = get_patched_freqtradebot(mocker, edge_conf) + edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy) mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock( return_value={ 'E/F': PairInfo(-0.01, 0.66, 3.71, 0.50, 1.71, 10, 60), @@ -138,9 +138,9 @@ def test_adjust(mocker, default_conf): assert(edge.adjust(pairs) == ['E/F', 'C/D']) -def test_stoploss(mocker, default_conf): - freqtrade = get_patched_freqtradebot(mocker, default_conf) - edge = Edge(default_conf, freqtrade.exchange, freqtrade.strategy) +def test_stoploss(mocker, edge_conf): + freqtrade = get_patched_freqtradebot(mocker, edge_conf) + edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy) mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock( return_value={ 'E/F': PairInfo(-0.01, 0.66, 3.71, 0.50, 1.71, 10, 60), @@ -234,12 +234,12 @@ def mocked_load_data(datadir, pairs=[], ticker_interval='0m', refresh_pairs=Fals return pairdata -def test_edge_process_downloaded_data(mocker, default_conf): - default_conf['datadir'] = None - freqtrade = get_patched_freqtradebot(mocker, default_conf) +def test_edge_process_downloaded_data(mocker, edge_conf): + edge_conf['datadir'] = None + freqtrade = get_patched_freqtradebot(mocker, edge_conf) mocker.patch('freqtrade.exchange.Exchange.get_fee', MagicMock(return_value=0.001)) mocker.patch('freqtrade.optimize.load_data', mocked_load_data) - edge = Edge(default_conf, freqtrade.exchange, freqtrade.strategy) + edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy) assert edge.calculate() assert len(edge._cached_pairs) == 2 diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index eb5336c61..04d00d00a 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -260,8 +260,8 @@ def test_edge_overrides_stake_amount(mocker, edge_conf) -> None: patch_edge(mocker) freqtrade = FreqtradeBot(edge_conf) - assert freqtrade._get_trade_stake_amount('NEO/BTC') == (0.001 * 0.01) / 0.20 - assert freqtrade._get_trade_stake_amount('LTC/BTC') == (0.001 * 0.01) / 0.20 + assert freqtrade._get_trade_stake_amount('NEO/BTC') == (999.9 * 0.5 * 0.01) / 0.20 + assert freqtrade._get_trade_stake_amount('LTC/BTC') == (999.9 * 0.5 * 0.01) / 0.21 def test_edge_overrides_stoploss(limit_buy_order, fee, markets, caplog, mocker, edge_conf) -> None: From e9305b6592ddcba35fef7d647f8d58ef79ccf40a Mon Sep 17 00:00:00 2001 From: misagh Date: Wed, 28 Nov 2018 15:36:32 +0100 Subject: [PATCH 03/31] position size fixed --- freqtrade/edge/__init__.py | 11 ++++++++--- freqtrade/freqtradebot.py | 4 +++- freqtrade/wallets.py | 22 ++++++++++++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/freqtrade/edge/__init__.py b/freqtrade/edge/__init__.py index f5961d9b4..f7e8e5ea9 100644 --- a/freqtrade/edge/__init__.py +++ b/freqtrade/edge/__init__.py @@ -159,11 +159,16 @@ class Edge(): return True - def stake_amount(self, pair: str, capital: float) -> float: + def stake_amount(self, pair: str, free_capital: float, total_capital: float) -> float: stoploss = self._cached_pairs[pair].stoploss - available_capital = capital * self._capital_percentage + available_capital = total_capital * self._capital_percentage allowed_capital_at_risk = round(available_capital * self._allowed_risk, 15) - position_size = abs(round((allowed_capital_at_risk / stoploss), 15)) + max_position_size = abs(round((allowed_capital_at_risk / stoploss), 15)) + position_size = min(max_position_size, free_capital) + logger.info( + 'position size is %s for pair %s, stoploss %s and available capital of %s.', + position_size, pair, stoploss, available_capital + ) return position_size def stoploss(self, pair: str) -> float: diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 937fa0d3f..90f100eac 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -334,7 +334,9 @@ class FreqtradeBot(object): """ if self.edge: stake_amount = self.edge.stake_amount( - pair, self.wallets.get_free(self.config['stake_currency']) + pair, + self.wallets.get_free(self.config['stake_currency']), + self.wallets.get_total(self.config['stake_currency']) ) return stake_amount else: diff --git a/freqtrade/wallets.py b/freqtrade/wallets.py index bf6f8b027..59d8fa3da 100644 --- a/freqtrade/wallets.py +++ b/freqtrade/wallets.py @@ -40,6 +40,28 @@ class Wallets(object): else: return 0 + def get_used(self, currency) -> float: + + if self.exchange._conf['dry_run']: + return 999.9 + + balance = self.wallets.get(currency) + if balance and balance.used: + return balance.used + else: + return 0 + + def get_total(self, currency) -> float: + + if self.exchange._conf['dry_run']: + return 999.9 + + balance = self.wallets.get(currency) + if balance and balance.total: + return balance.total + else: + return 0 + def update(self) -> None: balances = self.exchange.get_balances() From e698590bb25a3327b68a30897ae96bdec052cc1d Mon Sep 17 00:00:00 2001 From: misagh Date: Wed, 28 Nov 2018 20:04:56 +0100 Subject: [PATCH 04/31] avoid generating logs on each iteration --- freqtrade/edge/__init__.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/freqtrade/edge/__init__.py b/freqtrade/edge/__init__.py index f7e8e5ea9..0b4227ed0 100644 --- a/freqtrade/edge/__init__.py +++ b/freqtrade/edge/__init__.py @@ -53,6 +53,7 @@ class Edge(): self.edge_config = self.config.get('edge', {}) self._cached_pairs: Dict[str, Any] = {} # Keeps a list of pairs + self._final: list = [] # checking max_open_trades. it should be -1 as with Edge # the number of trades is determined by position size @@ -178,7 +179,6 @@ class Edge(): """ Filters out and sorts "pairs" according to Edge calculated pairs """ - final = [] for pair, info in self._cached_pairs.items(): if info.expectancy > float(self.edge_config.get('minimum_expectancy', 0.2)) and \ @@ -186,12 +186,14 @@ class Edge(): pair in pairs: final.append(pair) - if final: - logger.info('Edge validated only %s', final) - else: - logger.info('Edge removed all pairs as no pair with minimum expectancy was found !') + if self._final != final: + self._final = final + if self._final: + logger.info('Edge validated only %s', self._final) + else: + logger.info('Edge removed all pairs as no pair with minimum expectancy was found !') - return final + return self._final def _fill_calculable_fields(self, result: DataFrame) -> DataFrame: """ From a61daed8e95915f56ce36d5027335fac9b64f4bd Mon Sep 17 00:00:00 2001 From: misagh Date: Thu, 29 Nov 2018 12:24:04 +0100 Subject: [PATCH 05/31] logs enriched --- freqtrade/edge/__init__.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/freqtrade/edge/__init__.py b/freqtrade/edge/__init__.py index 0b4227ed0..f27309479 100644 --- a/freqtrade/edge/__init__.py +++ b/freqtrade/edge/__init__.py @@ -167,7 +167,10 @@ class Edge(): max_position_size = abs(round((allowed_capital_at_risk / stoploss), 15)) position_size = min(max_position_size, free_capital) logger.info( - 'position size is %s for pair %s, stoploss %s and available capital of %s.', + 'winrate: %s, expectancy: %s, position size: %s, pair: %s,' + ' stoploss: %s, available capital: %s.', + self._cached_pairs[pair].winrate, + self._cached_pairs[pair].expectancy, position_size, pair, stoploss, available_capital ) return position_size From 7767470af845279df6bea54436bf534ed7d41583 Mon Sep 17 00:00:00 2001 From: misagh Date: Fri, 30 Nov 2018 17:50:03 +0100 Subject: [PATCH 06/31] =?UTF-8?q?return=20stake=20amount=20of=20strategy?= =?UTF-8?q?=20if=20edge=20doesn=E2=80=99t=20have=20any?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- freqtrade/edge/__init__.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/freqtrade/edge/__init__.py b/freqtrade/edge/__init__.py index f27309479..74fabc409 100644 --- a/freqtrade/edge/__init__.py +++ b/freqtrade/edge/__init__.py @@ -161,6 +161,11 @@ class Edge(): return True def stake_amount(self, pair: str, free_capital: float, total_capital: float) -> float: + if pair not in self._cached_pairs: + logger.warning("cannot find %s in calculated pairs, " + "stake_amount of strategy is used instead.", pair) + return self.strategy.stake_amount + stoploss = self._cached_pairs[pair].stoploss available_capital = total_capital * self._capital_percentage allowed_capital_at_risk = round(available_capital * self._allowed_risk, 15) From 12471e012e1dd43155c84c063f33e6b7c4013dd6 Mon Sep 17 00:00:00 2001 From: misagh Date: Fri, 30 Nov 2018 17:59:51 +0100 Subject: [PATCH 07/31] added tests for position sizing --- freqtrade/edge/__init__.py | 2 +- freqtrade/tests/edge/test_edge.py | 40 ++++++++++++++++++++++++++++--- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/freqtrade/edge/__init__.py b/freqtrade/edge/__init__.py index 4800691e8..b76821da0 100644 --- a/freqtrade/edge/__init__.py +++ b/freqtrade/edge/__init__.py @@ -164,7 +164,7 @@ class Edge(): if pair not in self._cached_pairs: logger.warning("cannot find %s in calculated pairs, " "stake_amount of strategy is used instead.", pair) - return self.strategy.stake_amount + return self.config['stake_amount'] stoploss = self._cached_pairs[pair].stoploss available_capital = total_capital * self._capital_percentage diff --git a/freqtrade/tests/edge/test_edge.py b/freqtrade/tests/edge/test_edge.py index d5457f342..d453f6f27 100644 --- a/freqtrade/tests/edge/test_edge.py +++ b/freqtrade/tests/edge/test_edge.py @@ -5,6 +5,7 @@ import pytest import logging from freqtrade.tests.conftest import get_patched_freqtradebot from freqtrade.edge import Edge, PairInfo +from freqtrade import constants from pandas import DataFrame, to_datetime from freqtrade.strategy.interface import SellType from freqtrade.tests.optimize import (BTrade, BTContainer, _build_backtest_dataframe, @@ -152,9 +153,9 @@ def test_stoploss(mocker, edge_conf): assert edge.stoploss('E/F') == -0.01 -def test_nonexisting_stoploss(mocker, default_conf): - freqtrade = get_patched_freqtradebot(mocker, default_conf) - edge = Edge(default_conf, freqtrade.exchange, freqtrade.strategy) +def test_nonexisting_stoploss(mocker, edge_conf): + freqtrade = get_patched_freqtradebot(mocker, edge_conf) + edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy) mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock( return_value={ 'E/F': PairInfo(-0.01, 0.66, 3.71, 0.50, 1.71, 10, 60), @@ -164,6 +165,39 @@ def test_nonexisting_stoploss(mocker, default_conf): assert edge.stoploss('N/O') == -0.1 +def test_stake_amount(mocker, edge_conf): + freqtrade = get_patched_freqtradebot(mocker, edge_conf) + edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy) + mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock( + return_value={ + 'E/F': PairInfo(-0.02, 0.66, 3.71, 0.50, 1.71, 10, 60), + } + )) + free = 100 + total = 100 + assert edge.stake_amount('E/F', free, total) == 25 + + free = 20 + total = 100 + assert edge.stake_amount('E/F', free, total) == 20 + + free = 0 + total = 100 + assert edge.stake_amount('E/F', free, total) == 0 + + +def test_nonexisting_stake_amount(mocker, edge_conf): + freqtrade = get_patched_freqtradebot(mocker, edge_conf) + edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy) + mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock( + return_value={ + 'E/F': PairInfo(-0.01, 0.66, 3.71, 0.50, 1.71, 10, 60), + } + )) + + assert edge.stake_amount('N/O', 1, 2) == constants.UNLIMITED_STAKE_AMOUNT + + def _validate_ohlc(buy_ohlc_sell_matrice): for index, ohlc in enumerate(buy_ohlc_sell_matrice): # if not high < open < low or not high < close < low From 11101e66686e858a74b9e405a6bf870e90f582da Mon Sep 17 00:00:00 2001 From: misagh Date: Fri, 30 Nov 2018 18:07:45 +0100 Subject: [PATCH 08/31] config full aded --- config_binance.json.example | 2 +- config_full.json.example | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/config_binance.json.example b/config_binance.json.example index 7773a8c39..3d11f317a 100644 --- a/config_binance.json.example +++ b/config_binance.json.example @@ -59,7 +59,7 @@ "enabled": false, "process_throttle_secs": 3600, "calculate_since_number_of_days": 7, - "total_capital_in_stake_currency": 0.5, + "capital_available_percentage": 0.5, "allowed_risk": 0.01, "stoploss_range_min": -0.01, "stoploss_range_max": -0.1, diff --git a/config_full.json.example b/config_full.json.example index b0719bcc6..7e54eb5ca 100644 --- a/config_full.json.example +++ b/config_full.json.example @@ -67,7 +67,8 @@ "edge": { "enabled": false, "process_throttle_secs": 3600, - "calculate_since_number_of_days": 2, + "calculate_since_number_of_days": 7, + "capital_available_percentage": 0.5, "allowed_risk": 0.01, "stoploss_range_min": -0.01, "stoploss_range_max": -0.1, From aadc9f052ab63d9a168f3518a4891cc4718ea985 Mon Sep 17 00:00:00 2001 From: misagh Date: Fri, 30 Nov 2018 18:10:22 +0100 Subject: [PATCH 09/31] conf schema --- freqtrade/constants.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 055fee3b2..82f392990 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -191,6 +191,7 @@ CONF_SCHEMA = { "process_throttle_secs": {'type': 'integer', 'minimum': 600}, "calculate_since_number_of_days": {'type': 'integer'}, "allowed_risk": {'type': 'number'}, + "capital_available_percentage": {'type': 'number'}, "stoploss_range_min": {'type': 'number'}, "stoploss_range_max": {'type': 'number'}, "stoploss_range_step": {'type': 'number'}, From c61ede4182048611d74436bc0c610cc350ae0a76 Mon Sep 17 00:00:00 2001 From: misagh Date: Fri, 30 Nov 2018 18:20:29 +0100 Subject: [PATCH 10/31] documentation updated --- docs/edge.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/edge.md b/docs/edge.md index e5575554b..499b91e7b 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -82,9 +82,7 @@ Edge dictates the stake amount for each trade to the bot according to the follow Allowed capital at risk is calculated as follows: -**allowed capital at risk** = **total capital** X **allowed risk per trade** - -**total capital** is your stake amount. +**allowed capital at risk** = **capital_available_percentage** X **allowed risk per trade** **Stoploss** is calculated as described above against historical data. @@ -93,7 +91,7 @@ Your position size then will be: **position size** = **allowed capital at risk** / **stoploss** Example: -Let's say your stake amount is 3 ETH, you would allow 1% of risk for each trade. thus your allowed capital at risk would be **3 x 0.01 = 0.03 ETH**. Let's assume Edge has calculated that for **XLM/ETH** market your stoploss should be at 2%. So your position size will be **0.03 / 0.02= 1.5ETH**.
+Let's say the stake currency is ETH and you have 10 ETH on the exchange, your **capital_available_percentage** is 50% and you would allow 1% of risk for each trade. thus your available capital for trading is **10 x 0.5 = 5 ETH** and allowed capital at risk would be **5 x 0.01 = 0.05 ETH**. Let's assume Edge has calculated that for **XLM/ETH** market your stoploss should be at 2%. So your position size will be **0.05 / 0.02= 2.5ETH**.
## Configurations Edge has following configurations: @@ -111,6 +109,11 @@ Number of days of data against which Edge calculates Win Rate, Risk Reward and E Note that it downloads historical data so increasing this number would lead to slowing down the bot
(default to 7) +#### capital_available_percentage +This is the percentage of the total capital on exchange in stake currency.
+As an example if you have 100 USDT available in your wallet on the exchange and this value is 0.5 (which is 50%), then the bot will use a maximum amount of 50 USDT for trading and considers it as available capital. +(default to 0.5) + #### allowed_risk Percentage of allowed risk per trade
(default to 0.01 [1%]) From 7e86ec31be1e58ed93808ba660bc670ddc947859 Mon Sep 17 00:00:00 2001 From: misagh Date: Fri, 30 Nov 2018 18:23:16 +0100 Subject: [PATCH 11/31] tests added for wallet additional functions --- freqtrade/tests/test_wallets.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/freqtrade/tests/test_wallets.py b/freqtrade/tests/test_wallets.py index 88366a869..8d9adc74c 100644 --- a/freqtrade/tests/test_wallets.py +++ b/freqtrade/tests/test_wallets.py @@ -58,6 +58,8 @@ def test_sync_wallet_at_boot(mocker, default_conf): assert freqtrade.wallets.wallets['GAS'].used == 0.1 assert freqtrade.wallets.wallets['GAS'].total == 0.260439 assert freqtrade.wallets.get_free('GAS') == 0.270739 + assert freqtrade.wallets.get_used('GAS') == 0.1 + assert freqtrade.wallets.get_total('GAS') == 0.260439 def test_sync_wallet_missing_data(mocker, default_conf): From 4a2d60370c652884407c0ce66ce90c2021a73d9a Mon Sep 17 00:00:00 2001 From: misagh Date: Fri, 30 Nov 2018 18:28:18 +0100 Subject: [PATCH 12/31] adding dots at the end of sentences --- docs/edge.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/edge.md b/docs/edge.md index 499b91e7b..27afcd507 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -97,7 +97,7 @@ Let's say the stake currency is ETH and you have 10 ETH on the exchange, your ** Edge has following configurations: #### enabled -If true, then Edge will run periodically
+If true, then Edge will run periodically.
(default to false) #### process_throttle_secs @@ -106,24 +106,24 @@ How often should Edge run in seconds?
#### calculate_since_number_of_days Number of days of data against which Edge calculates Win Rate, Risk Reward and Expectancy -Note that it downloads historical data so increasing this number would lead to slowing down the bot
+Note that it downloads historical data so increasing this number would lead to slowing down the bot.
(default to 7) #### capital_available_percentage This is the percentage of the total capital on exchange in stake currency.
-As an example if you have 100 USDT available in your wallet on the exchange and this value is 0.5 (which is 50%), then the bot will use a maximum amount of 50 USDT for trading and considers it as available capital. +As an example if you have 100 USDT available in your wallet on the exchange and this value is 0.5 (which is 50%), then the bot will use a maximum amount of 50 USDT for trading and considers it as available capital.
(default to 0.5) #### allowed_risk -Percentage of allowed risk per trade
+Percentage of allowed risk per trade.
(default to 0.01 [1%]) #### stoploss_range_min -Minimum stoploss
+Minimum stoploss.
(default to -0.01) #### stoploss_range_max -Maximum stoploss
+Maximum stoploss.
(default to -0.10) #### stoploss_range_step From 9c987fdedd3b22794027af01d2ad01df22c71f54 Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 1 Dec 2018 10:56:33 +0100 Subject: [PATCH 13/31] variable name changed (_final_pairs) --- freqtrade/edge/__init__.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/freqtrade/edge/__init__.py b/freqtrade/edge/__init__.py index b76821da0..4c7ac7950 100644 --- a/freqtrade/edge/__init__.py +++ b/freqtrade/edge/__init__.py @@ -53,7 +53,7 @@ class Edge(): self.edge_config = self.config.get('edge', {}) self._cached_pairs: Dict[str, Any] = {} # Keeps a list of pairs - self._final: list = [] + self._final_pairs: list = [] # checking max_open_trades. it should be -1 as with Edge # the number of trades is determined by position size @@ -199,14 +199,14 @@ class Edge(): pair in pairs: final.append(pair) - if self._final != final: - self._final = final - if self._final: - logger.info('Edge validated only %s', self._final) + if self._final_pairs != final: + self._final_pairs = final + if self._final_pairs: + logger.info('Edge validated only %s', self._final_pairs) else: logger.info('Edge removed all pairs as no pair with minimum expectancy was found !') - return self._final + return self._final_pairs def _fill_calculable_fields(self, result: DataFrame) -> DataFrame: """ From 86d9457ea13f1f802646400ac7dbc991637d9daf Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 1 Dec 2018 10:58:05 +0100 Subject: [PATCH 14/31] removing unnecessary variable before returning the result --- freqtrade/freqtradebot.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 66e32ec4b..e687b4a8d 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -333,12 +333,11 @@ class FreqtradeBot(object): :return: float: Stake Amount """ if self.edge: - stake_amount = self.edge.stake_amount( + return self.edge.stake_amount( pair, self.wallets.get_free(self.config['stake_currency']), self.wallets.get_total(self.config['stake_currency']) ) - return stake_amount else: stake_amount = self.config['stake_amount'] From c4f17f1c4588a61cbc4e15d4ea1a6d7d66a6fefa Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 1 Dec 2018 10:58:47 +0100 Subject: [PATCH 15/31] config json updated --- config.json.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config.json.example b/config.json.example index bbd9648da..323ff711e 100644 --- a/config.json.example +++ b/config.json.example @@ -57,7 +57,7 @@ "enabled": false, "process_throttle_secs": 3600, "calculate_since_number_of_days": 7, - "total_capital_in_stake_currency": 0.5, + "capital_available_percentage": 0.5, "allowed_risk": 0.01, "stoploss_range_min": -0.01, "stoploss_range_max": -0.1, From 9c0be99ff7b4e99bbe88d2b0cee3fb1ce1d3d0e8 Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 1 Dec 2018 11:00:33 +0100 Subject: [PATCH 16/31] rounding float at the end --- freqtrade/edge/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/freqtrade/edge/__init__.py b/freqtrade/edge/__init__.py index 4c7ac7950..a7bf2199a 100644 --- a/freqtrade/edge/__init__.py +++ b/freqtrade/edge/__init__.py @@ -168,8 +168,8 @@ class Edge(): stoploss = self._cached_pairs[pair].stoploss available_capital = total_capital * self._capital_percentage - allowed_capital_at_risk = round(available_capital * self._allowed_risk, 15) - max_position_size = abs(round((allowed_capital_at_risk / stoploss), 15)) + allowed_capital_at_risk = available_capital * self._allowed_risk + max_position_size = abs(allowed_capital_at_risk / stoploss) position_size = min(max_position_size, free_capital) logger.info( 'winrate: %s, expectancy: %s, position size: %s, pair: %s,' @@ -178,7 +178,7 @@ class Edge(): self._cached_pairs[pair].expectancy, position_size, pair, stoploss, available_capital ) - return position_size + return round(position_size, 15) def stoploss(self, pair: str) -> float: if pair in self._cached_pairs: From 88d277ea557ba70156ae30e2ebc71817a6bbd22d Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 1 Dec 2018 11:08:18 +0100 Subject: [PATCH 17/31] adding required config for edge --- freqtrade/constants.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/freqtrade/constants.py b/freqtrade/constants.py index 82f392990..cd22815e9 100644 --- a/freqtrade/constants.py +++ b/freqtrade/constants.py @@ -200,7 +200,8 @@ CONF_SCHEMA = { "min_trade_number": {'type': 'number'}, "max_trade_duration_minute": {'type': 'integer'}, "remove_pumps": {'type': 'boolean'} - } + }, + 'required': ['process_throttle_secs', 'allowed_risk', 'capital_available_percentage'] } }, 'anyOf': [ From 4431e3bdb61bb7af1fa7db61d4d9e9f634d06b46 Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 1 Dec 2018 11:40:13 +0100 Subject: [PATCH 18/31] position size explanation enriched --- docs/edge.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/docs/edge.md b/docs/edge.md index 27afcd507..7ecd4e75b 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -90,8 +90,14 @@ Your position size then will be: **position size** = **allowed capital at risk** / **stoploss** -Example: -Let's say the stake currency is ETH and you have 10 ETH on the exchange, your **capital_available_percentage** is 50% and you would allow 1% of risk for each trade. thus your available capital for trading is **10 x 0.5 = 5 ETH** and allowed capital at risk would be **5 x 0.01 = 0.05 ETH**. Let's assume Edge has calculated that for **XLM/ETH** market your stoploss should be at 2%. So your position size will be **0.05 / 0.02= 2.5ETH**.
+Example:
+Let's say the stake currency is ETH and you have 10 ETH on the exchange, your **capital_available_percentage** is 50% and you would allow 1% of risk for each trade. thus your available capital for trading is **10 x 0.5 = 5 ETH** and allowed capital at risk would be **5 x 0.01 = 0.05 ETH**.
+Let's assume Edge has calculated that for **XLM/ETH** market your stoploss should be at 2%. So your position size will be **0.05 / 0.02 = 2.5ETH**.
+Bot takes a position of 2.5ETH on XLM/ETH (call it trade 1). Up next, you receive another buy signal while trade 1 is still open. This time on BTC/ETH market. Edge calculated stoploss for this market at 4%. So your position size would be 0.05 / 0.04 = 1.25ETH (call it trade 2).
+Note that available capital for trading didn’t change for trade 2 even if you had already trade 1. The available capital doesn’t mean the free amount on your wallet.
+Now you have two trades open. The Bot receives yet another buy signal for another market: **ADA/ETH**. This time the stoploss is calculated at 1%. So your position size is **0.05 / 0.01 = 5ETH**. But there are already 4ETH blocked in two previous trades. So the position size for this third trade would be 1ETH.
+Available capital doesn’t change before a position is sold. Let’s assume that trade 1 receives a sell signal and it is sold with a profit of 1ETH. Your total capital on exchange would be 11 ETH and the available capital for trading becomes 5.5ETH.
+So the Bot receives another buy signal for trade 4 with a stoploss at 2% then your position size would be 0.055 / 0.02 = 2.75 ## Configurations Edge has following configurations: From ee62adf4f7c4d2d323dd4740c2e2fa765d7846b7 Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 1 Dec 2018 11:41:30 +0100 Subject: [PATCH 19/31] highlight --- docs/edge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/edge.md b/docs/edge.md index 7ecd4e75b..5082b79d2 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -97,7 +97,7 @@ Bot takes a position of 2.5ETH on XLM/ETH (call it trade 1). Up next, you receiv Note that available capital for trading didn’t change for trade 2 even if you had already trade 1. The available capital doesn’t mean the free amount on your wallet.
Now you have two trades open. The Bot receives yet another buy signal for another market: **ADA/ETH**. This time the stoploss is calculated at 1%. So your position size is **0.05 / 0.01 = 5ETH**. But there are already 4ETH blocked in two previous trades. So the position size for this third trade would be 1ETH.
Available capital doesn’t change before a position is sold. Let’s assume that trade 1 receives a sell signal and it is sold with a profit of 1ETH. Your total capital on exchange would be 11 ETH and the available capital for trading becomes 5.5ETH.
-So the Bot receives another buy signal for trade 4 with a stoploss at 2% then your position size would be 0.055 / 0.02 = 2.75 +So the Bot receives another buy signal for trade 4 with a stoploss at 2% then your position size would be **0.055 / 0.02 = 2.75**. ## Configurations Edge has following configurations: From 1d41a917887b75188c2a31211346e1b778338318 Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 1 Dec 2018 11:48:41 +0100 Subject: [PATCH 20/31] =?UTF-8?q?stake=5Famount=20in=20case=20it=20doesn?= =?UTF-8?q?=E2=80=99t=20exist?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- freqtrade/edge/__init__.py | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/freqtrade/edge/__init__.py b/freqtrade/edge/__init__.py index a7bf2199a..e5f913e2d 100644 --- a/freqtrade/edge/__init__.py +++ b/freqtrade/edge/__init__.py @@ -161,23 +161,19 @@ class Edge(): return True def stake_amount(self, pair: str, free_capital: float, total_capital: float) -> float: - if pair not in self._cached_pairs: - logger.warning("cannot find %s in calculated pairs, " - "stake_amount of strategy is used instead.", pair) - return self.config['stake_amount'] - - stoploss = self._cached_pairs[pair].stoploss + stoploss = self.stoploss(pair) available_capital = total_capital * self._capital_percentage allowed_capital_at_risk = available_capital * self._allowed_risk max_position_size = abs(allowed_capital_at_risk / stoploss) position_size = min(max_position_size, free_capital) - logger.info( - 'winrate: %s, expectancy: %s, position size: %s, pair: %s,' - ' stoploss: %s, available capital: %s.', - self._cached_pairs[pair].winrate, - self._cached_pairs[pair].expectancy, - position_size, pair, stoploss, available_capital - ) + if pair in self._cached_pairs: + logger.info( + 'winrate: %s, expectancy: %s, position size: %s, pair: %s,' + ' stoploss: %s, available capital: %s.', + self._cached_pairs[pair].winrate, + self._cached_pairs[pair].expectancy, + position_size, pair, stoploss, available_capital + ) return round(position_size, 15) def stoploss(self, pair: str) -> float: From 33f1cc13b3a3db99287c805d4293c657dc4ee763 Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 1 Dec 2018 11:56:16 +0100 Subject: [PATCH 21/31] fixing tests --- freqtrade/tests/conftest.py | 1 - freqtrade/tests/edge/test_edge.py | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/freqtrade/tests/conftest.py b/freqtrade/tests/conftest.py index 75c8032f1..29297ac61 100644 --- a/freqtrade/tests/conftest.py +++ b/freqtrade/tests/conftest.py @@ -63,7 +63,6 @@ def patch_edge(mocker) -> None: 'LTC/BTC': PairInfo(-0.21, 0.66, 3.71, 0.50, 1.71, 11, 20), } )) - mocker.patch('freqtrade.edge.Edge.stoploss', MagicMock(return_value=-0.20)) mocker.patch('freqtrade.edge.Edge.calculate', MagicMock(return_value=True)) diff --git a/freqtrade/tests/edge/test_edge.py b/freqtrade/tests/edge/test_edge.py index d453f6f27..4b63ceb1a 100644 --- a/freqtrade/tests/edge/test_edge.py +++ b/freqtrade/tests/edge/test_edge.py @@ -191,11 +191,10 @@ def test_nonexisting_stake_amount(mocker, edge_conf): edge = Edge(edge_conf, freqtrade.exchange, freqtrade.strategy) mocker.patch('freqtrade.edge.Edge._cached_pairs', mocker.PropertyMock( return_value={ - 'E/F': PairInfo(-0.01, 0.66, 3.71, 0.50, 1.71, 10, 60), + 'E/F': PairInfo(-0.11, 0.66, 3.71, 0.50, 1.71, 10, 60), } )) - - assert edge.stake_amount('N/O', 1, 2) == constants.UNLIMITED_STAKE_AMOUNT + assert edge.stake_amount('N/O', 1, 2) == 0.1 def _validate_ohlc(buy_ohlc_sell_matrice): From bd673178cec320cc6343e84f1586c2cc0f0360f2 Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 1 Dec 2018 11:56:53 +0100 Subject: [PATCH 22/31] constants removed --- freqtrade/tests/edge/test_edge.py | 1 - 1 file changed, 1 deletion(-) diff --git a/freqtrade/tests/edge/test_edge.py b/freqtrade/tests/edge/test_edge.py index 4b63ceb1a..74227cfe8 100644 --- a/freqtrade/tests/edge/test_edge.py +++ b/freqtrade/tests/edge/test_edge.py @@ -5,7 +5,6 @@ import pytest import logging from freqtrade.tests.conftest import get_patched_freqtradebot from freqtrade.edge import Edge, PairInfo -from freqtrade import constants from pandas import DataFrame, to_datetime from freqtrade.strategy.interface import SellType from freqtrade.tests.optimize import (BTrade, BTContainer, _build_backtest_dataframe, From 7ddbaa70ad8a9f5643dbec74eac7065353838348 Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 1 Dec 2018 12:06:48 +0100 Subject: [PATCH 23/31] USDT to ETH conversion. 1 USDT = 1 ETH --- docs/edge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/edge.md b/docs/edge.md index 5082b79d2..829910484 100644 --- a/docs/edge.md +++ b/docs/edge.md @@ -117,7 +117,7 @@ Note that it downloads historical data so increasing this number would lead to s #### capital_available_percentage This is the percentage of the total capital on exchange in stake currency.
-As an example if you have 100 USDT available in your wallet on the exchange and this value is 0.5 (which is 50%), then the bot will use a maximum amount of 50 USDT for trading and considers it as available capital.
+As an example if you have 10 ETH available in your wallet on the exchange and this value is 0.5 (which is 50%), then the bot will use a maximum amount of 5 ETH for trading and considers it as available capital.
(default to 0.5) #### allowed_risk From 2d17346b0eec75df2597671c69e4e822eb8f16df Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 1 Dec 2018 13:01:51 +0100 Subject: [PATCH 24/31] explaining arbitrary stake amount in comment --- freqtrade/edge/__init__.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/freqtrade/edge/__init__.py b/freqtrade/edge/__init__.py index e5f913e2d..4dfcfc8ba 100644 --- a/freqtrade/edge/__init__.py +++ b/freqtrade/edge/__init__.py @@ -223,9 +223,13 @@ class Edge(): # 0.05% is 0.0005 # fee = 0.001 + # we set stake amount to an arbitraty amount. + # as it doesn't change the calculation. + # all returned values are relative. they are percentages. stake = 0.015 - fee = self.fee + + fee = self.fee open_fee = fee / 2 close_fee = fee / 2 From a5414b843703adf51eadbdba54f03397a91e4bf9 Mon Sep 17 00:00:00 2001 From: misagh Date: Sat, 1 Dec 2018 13:02:45 +0100 Subject: [PATCH 25/31] flake8 --- freqtrade/edge/__init__.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/freqtrade/edge/__init__.py b/freqtrade/edge/__init__.py index 4dfcfc8ba..a212c9849 100644 --- a/freqtrade/edge/__init__.py +++ b/freqtrade/edge/__init__.py @@ -223,12 +223,10 @@ class Edge(): # 0.05% is 0.0005 # fee = 0.001 - # we set stake amount to an arbitraty amount. + # we set stake amount to an arbitrary amount. # as it doesn't change the calculation. # all returned values are relative. they are percentages. stake = 0.015 - - fee = self.fee open_fee = fee / 2 close_fee = fee / 2 From b5192193fda4df5e3afa06399c22aa7a8f7889ba Mon Sep 17 00:00:00 2001 From: misagh Date: Mon, 3 Dec 2018 19:45:00 +0100 Subject: [PATCH 26/31] total amount passed to edge should consider open trades too --- freqtrade/freqtradebot.py | 3 ++- freqtrade/persistence.py | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index ccb45be2c..1e4b2e678 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -305,7 +305,8 @@ class FreqtradeBot(object): return self.edge.stake_amount( pair, self.wallets.get_free(self.config['stake_currency']), - self.wallets.get_total(self.config['stake_currency']) + self.wallets.get_total(self.config['stake_currency']) + + Trade.calc_total_open_trades_in_stake_currency() ) else: stake_amount = self.config['stake_amount'] diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 592a88acb..20ae8c43a 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -14,6 +14,7 @@ from sqlalchemy.exc import NoSuchModuleError from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm.scoping import scoped_session from sqlalchemy.orm.session import sessionmaker +from sqlalchemy import func from sqlalchemy.pool import StaticPool from freqtrade import OperationalException @@ -349,3 +350,13 @@ class Trade(_DECL_BASE): ) profit_percent = (close_trade_price / open_trade_price) - 1 return float(f"{profit_percent:.8f}") + + def calc_total_open_trades_in_stake_currency() -> float: + """ + Calculates total invested amount in open trades + in stake currency + """ + total_open_stake_amount = Trade.session.query(func.sum(Trade.stake_amount))\ + .filter(Trade.is_open.is_(True))\ + .scalar() + return total_open_stake_amount or 0 From 43bafc391f77e1b937b6e3b18ea74ab1d9b54e1e Mon Sep 17 00:00:00 2001 From: misagh Date: Mon, 3 Dec 2018 19:46:22 +0100 Subject: [PATCH 27/31] static method added --- freqtrade/persistence.py | 1 + 1 file changed, 1 insertion(+) diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index 20ae8c43a..aeab63f22 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -351,6 +351,7 @@ class Trade(_DECL_BASE): profit_percent = (close_trade_price / open_trade_price) - 1 return float(f"{profit_percent:.8f}") + @staticmethod def calc_total_open_trades_in_stake_currency() -> float: """ Calculates total invested amount in open trades From 108d9a111714c5d7a26aaa72980a03912e93819a Mon Sep 17 00:00:00 2001 From: misagh Date: Mon, 3 Dec 2018 19:55:37 +0100 Subject: [PATCH 28/31] function name refactored --- freqtrade/freqtradebot.py | 2 +- freqtrade/persistence.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 1e4b2e678..6baef76bc 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -306,7 +306,7 @@ class FreqtradeBot(object): pair, self.wallets.get_free(self.config['stake_currency']), self.wallets.get_total(self.config['stake_currency']) + - Trade.calc_total_open_trades_in_stake_currency() + Trade.total_open_trades_stakes() ) else: stake_amount = self.config['stake_amount'] diff --git a/freqtrade/persistence.py b/freqtrade/persistence.py index aeab63f22..71752d58e 100644 --- a/freqtrade/persistence.py +++ b/freqtrade/persistence.py @@ -352,7 +352,7 @@ class Trade(_DECL_BASE): return float(f"{profit_percent:.8f}") @staticmethod - def calc_total_open_trades_in_stake_currency() -> float: + def total_open_trades_stakes() -> float: """ Calculates total invested amount in open trades in stake currency From e7684b446b3c737a01da2d88dd0be08a4f4b78d8 Mon Sep 17 00:00:00 2001 From: misagh Date: Tue, 4 Dec 2018 17:05:35 +0100 Subject: [PATCH 29/31] capital in trade extracted to a separated argument --- freqtrade/edge/__init__.py | 10 +++++++--- freqtrade/freqtradebot.py | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/freqtrade/edge/__init__.py b/freqtrade/edge/__init__.py index a212c9849..49acbd3e7 100644 --- a/freqtrade/edge/__init__.py +++ b/freqtrade/edge/__init__.py @@ -160,19 +160,23 @@ class Edge(): return True - def stake_amount(self, pair: str, free_capital: float, total_capital: float) -> float: + def stake_amount(self, pair: str, free_capital: float, + total_capital: float, capital_in_trade: float) -> float: stoploss = self.stoploss(pair) - available_capital = total_capital * self._capital_percentage + available_capital = (total_capital + capital_in_trade) * self._capital_percentage allowed_capital_at_risk = available_capital * self._allowed_risk max_position_size = abs(allowed_capital_at_risk / stoploss) position_size = min(max_position_size, free_capital) if pair in self._cached_pairs: logger.info( 'winrate: %s, expectancy: %s, position size: %s, pair: %s,' + ' capital in trade: %s, free capital: %s, total capital: %s,' ' stoploss: %s, available capital: %s.', self._cached_pairs[pair].winrate, self._cached_pairs[pair].expectancy, - position_size, pair, stoploss, available_capital + position_size, pair, + capital_in_trade, free_capital, total_capital, + stoploss, available_capital ) return round(position_size, 15) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 6baef76bc..d782f4342 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -305,7 +305,7 @@ class FreqtradeBot(object): return self.edge.stake_amount( pair, self.wallets.get_free(self.config['stake_currency']), - self.wallets.get_total(self.config['stake_currency']) + + self.wallets.get_total(self.config['stake_currency']), Trade.total_open_trades_stakes() ) else: From 24f9ea29c605351ee61a7d4c8dbdabe7b158ca53 Mon Sep 17 00:00:00 2001 From: misagh Date: Tue, 4 Dec 2018 17:13:46 +0100 Subject: [PATCH 30/31] tests fixed --- freqtrade/tests/edge/test_edge.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/freqtrade/tests/edge/test_edge.py b/freqtrade/tests/edge/test_edge.py index 74227cfe8..008413ff1 100644 --- a/freqtrade/tests/edge/test_edge.py +++ b/freqtrade/tests/edge/test_edge.py @@ -174,15 +174,18 @@ def test_stake_amount(mocker, edge_conf): )) free = 100 total = 100 - assert edge.stake_amount('E/F', free, total) == 25 + in_trade = 25 + assert edge.stake_amount('E/F', free, total, in_trade) == 31.25 free = 20 total = 100 - assert edge.stake_amount('E/F', free, total) == 20 + in_trade = 25 + assert edge.stake_amount('E/F', free, total, in_trade) == 20 free = 0 total = 100 - assert edge.stake_amount('E/F', free, total) == 0 + in_trade = 25 + assert edge.stake_amount('E/F', free, total, in_trade) == 0 def test_nonexisting_stake_amount(mocker, edge_conf): @@ -193,7 +196,8 @@ def test_nonexisting_stake_amount(mocker, edge_conf): 'E/F': PairInfo(-0.11, 0.66, 3.71, 0.50, 1.71, 10, 60), } )) - assert edge.stake_amount('N/O', 1, 2) == 0.1 + # should use strategy stoploss + assert edge.stake_amount('N/O', 1, 2, 1) == 0.15 def _validate_ohlc(buy_ohlc_sell_matrice): From 0ea7dc92722e82f059f43d71538395bf5c06a03d Mon Sep 17 00:00:00 2001 From: misagh Date: Thu, 6 Dec 2018 13:51:06 +0100 Subject: [PATCH 31/31] test added for total open trade stake amount from schalchemy --- freqtrade/tests/test_freqtradebot.py | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/freqtrade/tests/test_freqtradebot.py b/freqtrade/tests/test_freqtradebot.py index e8d80b91f..ed3271838 100644 --- a/freqtrade/tests/test_freqtradebot.py +++ b/freqtrade/tests/test_freqtradebot.py @@ -342,6 +342,39 @@ def test_edge_should_ignore_strategy_stoploss(limit_buy_order, fee, markets, assert freqtrade.handle_trade(trade) is False +def test_total_open_trades_stakes(mocker, default_conf, ticker, + limit_buy_order, fee, markets) -> None: + patch_RPCManager(mocker) + patch_exchange(mocker) + default_conf['stake_amount'] = 0.0000098751 + mocker.patch.multiple( + 'freqtrade.exchange.Exchange', + get_ticker=ticker, + buy=MagicMock(return_value={'id': limit_buy_order['id']}), + get_fee=fee, + get_markets=markets + ) + freqtrade = FreqtradeBot(default_conf) + patch_get_signal(freqtrade) + freqtrade.create_trade() + trade = Trade.query.first() + + assert trade is not None + assert trade.stake_amount == 0.0000098751 + assert trade.is_open + assert trade.open_date is not None + + freqtrade.create_trade() + trade = Trade.query.order_by(Trade.id.desc()).first() + + assert trade is not None + assert trade.stake_amount == 0.0000098751 + assert trade.is_open + assert trade.open_date is not None + + assert Trade.total_open_trades_stakes() == 1.97502e-05 + + def test_get_min_pair_stake_amount(mocker, default_conf) -> None: patch_RPCManager(mocker) patch_exchange(mocker)