diff --git a/docs/strategy-advanced.md b/docs/strategy-advanced.md index f55cda5e2..cbb71e810 100644 --- a/docs/strategy-advanced.md +++ b/docs/strategy-advanced.md @@ -80,7 +80,7 @@ class AwesomeStrategy(IStrategy): ## Enter Tag When your strategy has multiple buy signals, you can name the signal that triggered. -Then you can access you buy signal on `custom_exit` +Then you can access your buy signal on `custom_exit` ```python def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: diff --git a/freqtrade/__init__.py b/freqtrade/__init__.py index 18b6c9130..db339bea3 100644 --- a/freqtrade/__init__.py +++ b/freqtrade/__init__.py @@ -1,5 +1,5 @@ """ Freqtrade bot """ -__version__ = '2023.1.dev' +__version__ = '2023.2.dev' if 'dev' in __version__: from pathlib import Path diff --git a/freqtrade/optimize/backtesting.py b/freqtrade/optimize/backtesting.py index 5e17eb45d..065a88f40 100644 --- a/freqtrade/optimize/backtesting.py +++ b/freqtrade/optimize/backtesting.py @@ -775,6 +775,11 @@ class Backtesting: trade: Optional[LocalTrade] = None, requested_rate: Optional[float] = None, requested_stake: Optional[float] = None) -> Optional[LocalTrade]: + """ + :param trade: Trade to adjust - initial entry if None + :param requested_rate: Adjusted entry rate + :param requested_stake: Stake amount for adjusted orders (`adjust_entry_price`). + """ current_time = row[DATE_IDX].to_pydatetime() entry_tag = row[ENTER_TAG_IDX] if len(row) >= ENTER_TAG_IDX + 1 else None @@ -800,7 +805,7 @@ class Backtesting: return trade time_in_force = self.strategy.order_time_in_force['entry'] - if stake_amount and (not min_stake_amount or stake_amount > min_stake_amount): + if stake_amount and (not min_stake_amount or stake_amount >= min_stake_amount): self.order_id_counter += 1 base_currency = self.exchange.get_pair_base_currency(pair) amount_p = (stake_amount / propose_rate) * leverage diff --git a/requirements.txt b/requirements.txt index dbe0e4fd4..00a748ce1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ numpy==1.24.1 pandas==1.5.3 pandas-ta==0.3.14b -ccxt==2.7.7 +ccxt==2.7.12 # Pin cryptography for now due to rust build errors with piwheels cryptography==38.0.1; platform_machine == 'armv7l' cryptography==39.0.0; platform_machine != 'armv7l' diff --git a/tests/exchange/test_ccxt_compat.py b/tests/exchange/test_ccxt_compat.py index 712f9eb6b..2ca92799f 100644 --- a/tests/exchange/test_ccxt_compat.py +++ b/tests/exchange/test_ccxt_compat.py @@ -43,7 +43,7 @@ EXCHANGES = { 'hasQuoteVolumeFutures': True, 'leverage_tiers_public': False, 'leverage_in_spot_market': False, - 'sample_order': { + 'sample_order': [{ "symbol": "SOLUSDT", "orderId": 3551312894, "orderListId": -1, @@ -60,7 +60,32 @@ EXCHANGES = { "workingTime": 1674493798550, "fills": [], "selfTradePreventionMode": "NONE", - } + }] + }, + 'binanceus': { + 'pair': 'BTC/USDT', + 'stake_currency': 'USDT', + 'hasQuoteVolume': True, + 'timeframe': '5m', + 'futures': False, + 'sample_order': [{ + "symbol": "SOLUSDT", + "orderId": 3551312894, + "orderListId": -1, + "clientOrderId": "x-R4DD3S8297c73a11ccb9dc8f2811ba", + "transactTime": 1674493798550, + "price": "15.00000000", + "origQty": "1.00000000", + "executedQty": "0.00000000", + "cummulativeQuoteQty": "0.00000000", + "status": "NEW", + "timeInForce": "GTC", + "type": "LIMIT", + "side": "BUY", + "workingTime": 1674493798550, + "fills": [], + "selfTradePreventionMode": "NONE", + }] }, 'kraken': { 'pair': 'BTC/USDT', @@ -77,6 +102,40 @@ EXCHANGES = { 'timeframe': '5m', 'leverage_tiers_public': False, 'leverage_in_spot_market': True, + 'sample_order': [ + {'id': '63d6742d0adc5570001d2bbf7'}, # create order + { + 'id': '63d6742d0adc5570001d2bbf7', + 'symbol': 'NAKA-USDT', + 'opType': 'DEAL', + 'type': 'limit', + 'side': 'buy', + 'price': '30', + 'size': '0.1', + 'funds': '0', + 'dealFunds': '0.032626', + 'dealSize': '0.1', + 'fee': '0.000065252', + 'feeCurrency': 'USDT', + 'stp': '', + 'stop': '', + 'stopTriggered': False, + 'stopPrice': '0', + 'timeInForce': 'GTC', + 'postOnly': False, + 'hidden': False, + 'iceberg': False, + 'visibleSize': '0', + 'cancelAfter': 0, + 'channel': 'API', + 'clientOid': '0a053870-11bf-41e5-be61-b272a4cb62e1', + 'remark': None, + 'tags': 'partner:ccxt', + 'isActive': False, + 'cancelExist': False, + 'createdAt': 1674493798550, + 'tradeType': 'TRADE' + }], }, 'gateio': { 'pair': 'BTC/USDT', @@ -242,14 +301,18 @@ class TestCCXTExchange(): def test_ccxt_order_parse(self, exchange: EXCHANGE_FIXTURE_TYPE): exch, exchange_name = exchange - if stuff := EXCHANGES[exchange_name].get('sample_order'): - - po = exch._api.parse_order(stuff) - assert po['timestamp'] == 1674493798550 - assert isinstance(po['timestamp'], int) - assert isinstance(po['price'], float) - assert isinstance(po['amount'], float) - assert isinstance(po['status'], str) + if orders := EXCHANGES[exchange_name].get('sample_order'): + for order in orders: + po = exch._api.parse_order(order) + assert isinstance(po['id'], str) + assert po['id'] is not None + if len(order.keys()) > 1: + assert po['timestamp'] == 1674493798550 + assert isinstance(po['datetime'], str) + assert isinstance(po['timestamp'], int) + assert isinstance(po['price'], float) + assert isinstance(po['amount'], float) + assert isinstance(po['status'], str) else: pytest.skip(f"No sample order available for exchange {exchange_name}")