From 86f3b649b91f2033d8270d96ab5ff71a0a365bb1 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 24 Apr 2024 06:42:17 +0200 Subject: [PATCH 01/15] Update security warning in docker section --- docs/rest-api.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/rest-api.md b/docs/rest-api.md index 8acad7d8a..ab5e9db9f 100644 --- a/docs/rest-api.md +++ b/docs/rest-api.md @@ -89,7 +89,8 @@ Make sure that the following 2 lines are available in your docker-compose file: ``` !!! Danger "Security warning" - By using `8080:8080` in the docker port mapping, the API will be available to everyone connecting to the server under the correct port, so others may be able to control your bot. + By using `"8080:8080"` (or `"0.0.0.0:8080:8080"`) in the docker port mapping, the API will be available to everyone connecting to the server under the correct port, so others may be able to control your bot. + This **may** be safe if you're running the bot in a secure environment (like your home network), but it's not recommended to expose the API to the internet. ## Rest API From fa6c17c067b6696f203e21b5d2dedb76469a9f22 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 24 Apr 2024 07:00:17 +0200 Subject: [PATCH 02/15] Remove mutable default-args from generate-candlestick --- freqtrade/plot/plotting.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/freqtrade/plot/plotting.py b/freqtrade/plot/plotting.py index e5173a29e..4d29337a7 100644 --- a/freqtrade/plot/plotting.py +++ b/freqtrade/plot/plotting.py @@ -440,8 +440,8 @@ def create_scatter( def generate_candlestick_graph( pair: str, data: pd.DataFrame, trades: Optional[pd.DataFrame] = None, *, - indicators1: List[str] = [], indicators2: List[str] = [], - plot_config: Dict[str, Dict] = {}, + indicators1: Optional[List[str]] = None, indicators2: Optional[List[str]] = None, + plot_config: Optional[Dict[str, Dict]] = None, ) -> go.Figure: """ Generate the graph from the data generated by Backtesting or from DB @@ -454,7 +454,11 @@ def generate_candlestick_graph( :param plot_config: Dict of Dicts containing advanced plot configuration :return: Plotly figure """ - plot_config = create_plotconfig(indicators1, indicators2, plot_config) + plot_config = create_plotconfig( + indicators1 or [], + indicators2 or [], + plot_config or {}, + ) rows = 2 + len(plot_config['subplots']) row_widths = [1 for _ in plot_config['subplots']] # Define the graph From 365b9c9cfeb5552df5f7b7a46de87f788c5a5e49 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 24 Apr 2024 07:02:26 +0200 Subject: [PATCH 03/15] kwargs for re.sub count --- freqtrade/data/history/datahandlers/idatahandler.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/data/history/datahandlers/idatahandler.py b/freqtrade/data/history/datahandlers/idatahandler.py index fbaded640..cff26760f 100644 --- a/freqtrade/data/history/datahandlers/idatahandler.py +++ b/freqtrade/data/history/datahandlers/idatahandler.py @@ -302,8 +302,8 @@ class IDataHandler(ABC): Rebuild pair name from filename Assumes a asset name of max. 7 length to also support BTC-PERP and BTC-PERP:USD names. """ - res = re.sub(r'^(([A-Za-z\d]{1,10})|^([A-Za-z\-]{1,6}))(_)', r'\g<1>/', pair, 1) - res = re.sub('_', ':', res, 1) + res = re.sub(r'^(([A-Za-z\d]{1,10})|^([A-Za-z\-]{1,6}))(_)', r'\g<1>/', pair, count=1) + res = re.sub('_', ':', res, count=1) return res def ohlcv_load(self, pair, timeframe: str, From 652819309dff4760800f41553937693d49e55bbc Mon Sep 17 00:00:00 2001 From: xmatthias <5024695+xmatthias@users.noreply.github.com> Date: Thu, 25 Apr 2024 03:02:27 +0000 Subject: [PATCH 04/15] chore: update pre-commit hooks --- .../exchange/binance_leverage_tiers.json | 972 +++++++++++++----- 1 file changed, 721 insertions(+), 251 deletions(-) diff --git a/freqtrade/exchange/binance_leverage_tiers.json b/freqtrade/exchange/binance_leverage_tiers.json index e47854811..abc135395 100644 --- a/freqtrade/exchange/binance_leverage_tiers.json +++ b/freqtrade/exchange/binance_leverage_tiers.json @@ -7547,6 +7547,136 @@ } } ], + "BOME/USDC:USDC": [ + { + "tier": 1.0, + "currency": "USDC", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDC", + "minNotional": 5000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "2", + "initialLeverage": "25", + "notionalCap": "50000", + "notionalFloor": "5000", + "maintMarginRatio": "0.02", + "cum": "50.0" + } + }, + { + "tier": 3.0, + "currency": "USDC", + "minNotional": 50000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "3", + "initialLeverage": "20", + "notionalCap": "600000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "300.0" + } + }, + { + "tier": 4.0, + "currency": "USDC", + "minNotional": 600000.0, + "maxNotional": 1200000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "4", + "initialLeverage": "10", + "notionalCap": "1200000", + "notionalFloor": "600000", + "maintMarginRatio": "0.05", + "cum": "15300.0" + } + }, + { + "tier": 5.0, + "currency": "USDC", + "minNotional": 1200000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "5", + "initialLeverage": "5", + "notionalCap": "3000000", + "notionalFloor": "1200000", + "maintMarginRatio": "0.1", + "cum": "75300.0" + } + }, + { + "tier": 6.0, + "currency": "USDC", + "minNotional": 3000000.0, + "maxNotional": 4000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "6", + "initialLeverage": "4", + "notionalCap": "4000000", + "notionalFloor": "3000000", + "maintMarginRatio": "0.125", + "cum": "150300.0" + } + }, + { + "tier": 7.0, + "currency": "USDC", + "minNotional": 4000000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "7", + "initialLeverage": "2", + "notionalCap": "6000000", + "notionalFloor": "4000000", + "maintMarginRatio": "0.25", + "cum": "650300.0" + } + }, + { + "tier": 8.0, + "currency": "USDC", + "minNotional": 6000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "8", + "initialLeverage": "1", + "notionalCap": "10000000", + "notionalFloor": "6000000", + "maintMarginRatio": "0.5", + "cum": "2150300.0" + } + } + ], "BOME/USDT:USDT": [ { "tier": 1.0, @@ -21463,6 +21593,152 @@ } } ], + "MATIC/USDC:USDC": [ + { + "tier": 1.0, + "currency": "USDC", + "minNotional": 0.0, + "maxNotional": 10000.0, + "maintenanceMarginRate": 0.006, + "maxLeverage": 75.0, + "info": { + "bracket": "1", + "initialLeverage": "75", + "notionalCap": "10000", + "notionalFloor": "0", + "maintMarginRatio": "0.006", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDC", + "minNotional": 10000.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.007, + "maxLeverage": 50.0, + "info": { + "bracket": "2", + "initialLeverage": "50", + "notionalCap": "25000", + "notionalFloor": "10000", + "maintMarginRatio": "0.007", + "cum": "10.0" + } + }, + { + "tier": 3.0, + "currency": "USDC", + "minNotional": 25000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 25.0, + "info": { + "bracket": "3", + "initialLeverage": "25", + "notionalCap": "600000", + "notionalFloor": "25000", + "maintMarginRatio": "0.01", + "cum": "85.0" + } + }, + { + "tier": 4.0, + "currency": "USDC", + "minNotional": 600000.0, + "maxNotional": 900000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "4", + "initialLeverage": "20", + "notionalCap": "900000", + "notionalFloor": "600000", + "maintMarginRatio": "0.025", + "cum": "9085.0" + } + }, + { + "tier": 5.0, + "currency": "USDC", + "minNotional": 900000.0, + "maxNotional": 1800000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "5", + "initialLeverage": "10", + "notionalCap": "1800000", + "notionalFloor": "900000", + "maintMarginRatio": "0.05", + "cum": "31585.0" + } + }, + { + "tier": 6.0, + "currency": "USDC", + "minNotional": 1800000.0, + "maxNotional": 4800000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "6", + "initialLeverage": "5", + "notionalCap": "4800000", + "notionalFloor": "1800000", + "maintMarginRatio": "0.1", + "cum": "121585.0" + } + }, + { + "tier": 7.0, + "currency": "USDC", + "minNotional": 4800000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "7", + "initialLeverage": "4", + "notionalCap": "6000000", + "notionalFloor": "4800000", + "maintMarginRatio": "0.125", + "cum": "241585.0" + } + }, + { + "tier": 8.0, + "currency": "USDC", + "minNotional": 6000000.0, + "maxNotional": 18000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "8", + "initialLeverage": "2", + "notionalCap": "18000000", + "notionalFloor": "6000000", + "maintMarginRatio": "0.25", + "cum": "991585.0" + } + }, + { + "tier": 9.0, + "currency": "USDC", + "minNotional": 18000000.0, + "maxNotional": 30000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "9", + "initialLeverage": "1", + "notionalCap": "30000000", + "notionalFloor": "18000000", + "maintMarginRatio": "0.5", + "cum": "5491585.0" + } + } + ], "MATIC/USDT:USDT": [ { "tier": 1.0, @@ -24430,13 +24706,13 @@ "tier": 2.0, "currency": "USDT", "minNotional": 5000.0, - "maxNotional": 25000.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "2", "initialLeverage": "25", - "notionalCap": "25000", + "notionalCap": "50000", "notionalFloor": "5000", "maintMarginRatio": "0.02", "cum": "25.0" @@ -24445,97 +24721,97 @@ { "tier": 3.0, "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 80000.0, + "minNotional": 50000.0, + "maxNotional": 150000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "3", "initialLeverage": "20", - "notionalCap": "80000", - "notionalFloor": "25000", + "notionalCap": "150000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", - "cum": "150.0" + "cum": "275.0" } }, { "tier": 4.0, "currency": "USDT", - "minNotional": 80000.0, - "maxNotional": 800000.0, + "minNotional": 150000.0, + "maxNotional": 1500000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "notionalCap": "800000", - "notionalFloor": "80000", + "notionalCap": "1500000", + "notionalFloor": "150000", "maintMarginRatio": "0.05", - "cum": "2150.0" + "cum": "4025.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 800000.0, - "maxNotional": 1600000.0, + "minNotional": 1500000.0, + "maxNotional": 3000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "notionalCap": "1600000", - "notionalFloor": "800000", + "notionalCap": "3000000", + "notionalFloor": "1500000", "maintMarginRatio": "0.1", - "cum": "42150.0" + "cum": "79025.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1600000.0, - "maxNotional": 2000000.0, + "minNotional": 3000000.0, + "maxNotional": 3750000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "notionalCap": "2000000", - "notionalFloor": "1600000", + "notionalCap": "3750000", + "notionalFloor": "3000000", "maintMarginRatio": "0.125", - "cum": "82150.0" + "cum": "154025.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 4000000.0, + "minNotional": 3750000.0, + "maxNotional": 7500000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "7", "initialLeverage": "2", - "notionalCap": "4000000", - "notionalFloor": "2000000", + "notionalCap": "7500000", + "notionalFloor": "3750000", "maintMarginRatio": "0.25", - "cum": "332150.0" + "cum": "622775.0" } }, { "tier": 8.0, "currency": "USDT", - "minNotional": 4000000.0, - "maxNotional": 8000000.0, + "minNotional": 7500000.0, + "maxNotional": 15000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "8", "initialLeverage": "1", - "notionalCap": "8000000", - "notionalFloor": "4000000", + "notionalCap": "15000000", + "notionalFloor": "7500000", "maintMarginRatio": "0.5", - "cum": "1332150.0" + "cum": "2497775.0" } } ], @@ -25553,14 +25829,14 @@ "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 20.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "50", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.02", + "maintMarginRatio": "0.015", "cum": "0.0" } }, @@ -25569,14 +25845,14 @@ "currency": "USDT", "minNotional": 5000.0, "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 15.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "2", - "initialLeverage": "15", + "initialLeverage": "25", "notionalCap": "25000", "notionalFloor": "5000", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "25.0" } }, @@ -25584,80 +25860,96 @@ "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 200000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxNotional": 80000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "3", - "initialLeverage": "10", - "notionalCap": "200000", + "initialLeverage": "20", + "notionalCap": "80000", "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "650.0" + "maintMarginRatio": "0.025", + "cum": "150.0" } }, { "tier": 4.0, "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 80000.0, + "maxNotional": 800000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "200000", - "maintMarginRatio": "0.1", - "cum": "10650.0" + "initialLeverage": "10", + "notionalCap": "800000", + "notionalFloor": "80000", + "maintMarginRatio": "0.05", + "cum": "2150.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "minNotional": 800000.0, + "maxNotional": 1600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "23150.0" + "initialLeverage": "5", + "notionalCap": "1600000", + "notionalFloor": "800000", + "maintMarginRatio": "0.1", + "cum": "42150.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 3000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, + "minNotional": 1600000.0, + "maxNotional": 2000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, "info": { "bracket": "6", - "initialLeverage": "2", - "notionalCap": "3000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "148150.0" + "initialLeverage": "4", + "notionalCap": "2000000", + "notionalFloor": "1600000", + "maintMarginRatio": "0.125", + "cum": "82150.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 3000000.0, - "maxNotional": 5000000.0, + "minNotional": 2000000.0, + "maxNotional": 4000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "7", + "initialLeverage": "2", + "notionalCap": "4000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "332150.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 4000000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "7", + "bracket": "8", "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "3000000", + "notionalCap": "8000000", + "notionalFloor": "4000000", "maintMarginRatio": "0.5", - "cum": "898150.0" + "cum": "1332150.0" } } ], @@ -27589,14 +27881,14 @@ "currency": "USDT", "minNotional": 0.0, "maxNotional": 5000.0, - "maintenanceMarginRate": 0.02, - "maxLeverage": 20.0, + "maintenanceMarginRate": 0.015, + "maxLeverage": 50.0, "info": { "bracket": "1", - "initialLeverage": "20", + "initialLeverage": "50", "notionalCap": "5000", "notionalFloor": "0", - "maintMarginRatio": "0.02", + "maintMarginRatio": "0.015", "cum": "0.0" } }, @@ -27604,96 +27896,112 @@ "tier": 2.0, "currency": "USDT", "minNotional": 5000.0, - "maxNotional": 50000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 15.0, + "maxNotional": 25000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "2", - "initialLeverage": "15", - "notionalCap": "50000", + "initialLeverage": "25", + "notionalCap": "25000", "notionalFloor": "5000", - "maintMarginRatio": "0.025", + "maintMarginRatio": "0.02", "cum": "25.0" } }, { "tier": 3.0, "currency": "USDT", - "minNotional": 50000.0, - "maxNotional": 200000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "minNotional": 25000.0, + "maxNotional": 80000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "3", - "initialLeverage": "10", - "notionalCap": "200000", - "notionalFloor": "50000", - "maintMarginRatio": "0.05", - "cum": "1275.0" + "initialLeverage": "20", + "notionalCap": "80000", + "notionalFloor": "25000", + "maintMarginRatio": "0.025", + "cum": "150.0" } }, { "tier": 4.0, "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 80000.0, + "maxNotional": 800000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "4", - "initialLeverage": "5", - "notionalCap": "500000", - "notionalFloor": "200000", - "maintMarginRatio": "0.1", - "cum": "11275.0" + "initialLeverage": "10", + "notionalCap": "800000", + "notionalFloor": "80000", + "maintMarginRatio": "0.05", + "cum": "2150.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "minNotional": 800000.0, + "maxNotional": 1600000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "5", - "initialLeverage": "4", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.125", - "cum": "23775.0" + "initialLeverage": "5", + "notionalCap": "1600000", + "notionalFloor": "800000", + "maintMarginRatio": "0.1", + "cum": "42150.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1000000.0, + "minNotional": 1600000.0, "maxNotional": 2000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, "info": { "bracket": "6", - "initialLeverage": "2", + "initialLeverage": "4", "notionalCap": "2000000", - "notionalFloor": "1000000", - "maintMarginRatio": "0.25", - "cum": "148775.0" + "notionalFloor": "1600000", + "maintMarginRatio": "0.125", + "cum": "82150.0" } }, { "tier": 7.0, "currency": "USDT", "minNotional": 2000000.0, - "maxNotional": 5000000.0, + "maxNotional": 4000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "7", + "initialLeverage": "2", + "notionalCap": "4000000", + "notionalFloor": "2000000", + "maintMarginRatio": "0.25", + "cum": "332150.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 4000000.0, + "maxNotional": 8000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "7", + "bracket": "8", "initialLeverage": "1", - "notionalCap": "5000000", - "notionalFloor": "2000000", + "notionalCap": "8000000", + "notionalFloor": "4000000", "maintMarginRatio": "0.5", - "cum": "648775.0" + "cum": "1332150.0" } } ], @@ -28273,95 +28581,111 @@ "currency": "USDT", "minNotional": 5000.0, "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "25", "notionalCap": "25000", "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "50.0" + "maintMarginRatio": "0.02", + "cum": "25.0" } }, { "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", + "initialLeverage": "20", + "notionalCap": "50000", "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "675.0" + "maintMarginRatio": "0.025", + "cum": "150.0" } }, { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 200000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 50000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "4", - "initialLeverage": "5", - "notionalCap": "200000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5675.0" + "initialLeverage": "10", + "notionalCap": "500000", + "notionalFloor": "50000", + "maintMarginRatio": "0.05", + "cum": "1400.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "5", - "initialLeverage": "4", - "notionalCap": "500000", - "notionalFloor": "200000", - "maintMarginRatio": "0.125", - "cum": "10675.0" + "initialLeverage": "5", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.1", + "cum": "26400.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, + "minNotional": 1000000.0, + "maxNotional": 1250000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, "info": { "bracket": "6", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.25", - "cum": "73175.0" + "initialLeverage": "4", + "notionalCap": "1250000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.125", + "cum": "51400.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, + "minNotional": 1250000.0, + "maxNotional": 2500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "7", + "initialLeverage": "2", + "notionalCap": "2500000", + "notionalFloor": "1250000", + "maintMarginRatio": "0.25", + "cum": "207650.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 2500000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "7", + "bracket": "8", "initialLeverage": "1", - "notionalCap": "2000000", - "notionalFloor": "1000000", + "notionalCap": "5000000", + "notionalFloor": "2500000", "maintMarginRatio": "0.5", - "cum": "323175.0" + "cum": "832650.0" } } ], @@ -31751,6 +32075,136 @@ } } ], + "TIA/USDC:USDC": [ + { + "tier": 1.0, + "currency": "USDC", + "minNotional": 0.0, + "maxNotional": 5000.0, + "maintenanceMarginRate": 0.01, + "maxLeverage": 50.0, + "info": { + "bracket": "1", + "initialLeverage": "50", + "notionalCap": "5000", + "notionalFloor": "0", + "maintMarginRatio": "0.01", + "cum": "0.0" + } + }, + { + "tier": 2.0, + "currency": "USDC", + "minNotional": 5000.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, + "info": { + "bracket": "2", + "initialLeverage": "25", + "notionalCap": "50000", + "notionalFloor": "5000", + "maintMarginRatio": "0.02", + "cum": "50.0" + } + }, + { + "tier": 3.0, + "currency": "USDC", + "minNotional": 50000.0, + "maxNotional": 600000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, + "info": { + "bracket": "3", + "initialLeverage": "20", + "notionalCap": "600000", + "notionalFloor": "50000", + "maintMarginRatio": "0.025", + "cum": "300.0" + } + }, + { + "tier": 4.0, + "currency": "USDC", + "minNotional": 600000.0, + "maxNotional": 1200000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, + "info": { + "bracket": "4", + "initialLeverage": "10", + "notionalCap": "1200000", + "notionalFloor": "600000", + "maintMarginRatio": "0.05", + "cum": "15300.0" + } + }, + { + "tier": 5.0, + "currency": "USDC", + "minNotional": 1200000.0, + "maxNotional": 3000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, + "info": { + "bracket": "5", + "initialLeverage": "5", + "notionalCap": "3000000", + "notionalFloor": "1200000", + "maintMarginRatio": "0.1", + "cum": "75300.0" + } + }, + { + "tier": 6.0, + "currency": "USDC", + "minNotional": 3000000.0, + "maxNotional": 4000000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, + "info": { + "bracket": "6", + "initialLeverage": "4", + "notionalCap": "4000000", + "notionalFloor": "3000000", + "maintMarginRatio": "0.125", + "cum": "150300.0" + } + }, + { + "tier": 7.0, + "currency": "USDC", + "minNotional": 4000000.0, + "maxNotional": 6000000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "7", + "initialLeverage": "2", + "notionalCap": "6000000", + "notionalFloor": "4000000", + "maintMarginRatio": "0.25", + "cum": "650300.0" + } + }, + { + "tier": 8.0, + "currency": "USDC", + "minNotional": 6000000.0, + "maxNotional": 10000000.0, + "maintenanceMarginRate": 0.5, + "maxLeverage": 1.0, + "info": { + "bracket": "8", + "initialLeverage": "1", + "notionalCap": "10000000", + "notionalFloor": "6000000", + "maintMarginRatio": "0.5", + "cum": "2150300.0" + } + } + ], "TIA/USDT:USDT": [ { "tier": 1.0, @@ -33823,95 +34277,111 @@ "currency": "USDT", "minNotional": 5000.0, "maxNotional": 25000.0, - "maintenanceMarginRate": 0.025, - "maxLeverage": 20.0, + "maintenanceMarginRate": 0.02, + "maxLeverage": 25.0, "info": { "bracket": "2", - "initialLeverage": "20", + "initialLeverage": "25", "notionalCap": "25000", "notionalFloor": "5000", - "maintMarginRatio": "0.025", - "cum": "50.0" + "maintMarginRatio": "0.02", + "cum": "25.0" } }, { "tier": 3.0, "currency": "USDT", "minNotional": 25000.0, - "maxNotional": 100000.0, - "maintenanceMarginRate": 0.05, - "maxLeverage": 10.0, + "maxNotional": 50000.0, + "maintenanceMarginRate": 0.025, + "maxLeverage": 20.0, "info": { "bracket": "3", - "initialLeverage": "10", - "notionalCap": "100000", + "initialLeverage": "20", + "notionalCap": "50000", "notionalFloor": "25000", - "maintMarginRatio": "0.05", - "cum": "675.0" + "maintMarginRatio": "0.025", + "cum": "150.0" } }, { "tier": 4.0, "currency": "USDT", - "minNotional": 100000.0, - "maxNotional": 200000.0, - "maintenanceMarginRate": 0.1, - "maxLeverage": 5.0, + "minNotional": 50000.0, + "maxNotional": 500000.0, + "maintenanceMarginRate": 0.05, + "maxLeverage": 10.0, "info": { "bracket": "4", - "initialLeverage": "5", - "notionalCap": "200000", - "notionalFloor": "100000", - "maintMarginRatio": "0.1", - "cum": "5675.0" + "initialLeverage": "10", + "notionalCap": "500000", + "notionalFloor": "50000", + "maintMarginRatio": "0.05", + "cum": "1400.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 200000.0, - "maxNotional": 500000.0, - "maintenanceMarginRate": 0.125, - "maxLeverage": 4.0, + "minNotional": 500000.0, + "maxNotional": 1000000.0, + "maintenanceMarginRate": 0.1, + "maxLeverage": 5.0, "info": { "bracket": "5", - "initialLeverage": "4", - "notionalCap": "500000", - "notionalFloor": "200000", - "maintMarginRatio": "0.125", - "cum": "10675.0" + "initialLeverage": "5", + "notionalCap": "1000000", + "notionalFloor": "500000", + "maintMarginRatio": "0.1", + "cum": "26400.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 500000.0, - "maxNotional": 1000000.0, - "maintenanceMarginRate": 0.25, - "maxLeverage": 2.0, + "minNotional": 1000000.0, + "maxNotional": 1250000.0, + "maintenanceMarginRate": 0.125, + "maxLeverage": 4.0, "info": { "bracket": "6", - "initialLeverage": "2", - "notionalCap": "1000000", - "notionalFloor": "500000", - "maintMarginRatio": "0.25", - "cum": "73175.0" + "initialLeverage": "4", + "notionalCap": "1250000", + "notionalFloor": "1000000", + "maintMarginRatio": "0.125", + "cum": "51400.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 1000000.0, - "maxNotional": 2000000.0, + "minNotional": 1250000.0, + "maxNotional": 2500000.0, + "maintenanceMarginRate": 0.25, + "maxLeverage": 2.0, + "info": { + "bracket": "7", + "initialLeverage": "2", + "notionalCap": "2500000", + "notionalFloor": "1250000", + "maintMarginRatio": "0.25", + "cum": "207650.0" + } + }, + { + "tier": 8.0, + "currency": "USDT", + "minNotional": 2500000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { - "bracket": "7", + "bracket": "8", "initialLeverage": "1", - "notionalCap": "2000000", - "notionalFloor": "1000000", + "notionalCap": "5000000", + "notionalFloor": "2500000", "maintMarginRatio": "0.5", - "cum": "323175.0" + "cum": "832650.0" } } ], @@ -34294,13 +34764,13 @@ "tier": 2.0, "currency": "USDT", "minNotional": 5000.0, - "maxNotional": 25000.0, + "maxNotional": 50000.0, "maintenanceMarginRate": 0.02, "maxLeverage": 25.0, "info": { "bracket": "2", "initialLeverage": "25", - "notionalCap": "25000", + "notionalCap": "50000", "notionalFloor": "5000", "maintMarginRatio": "0.02", "cum": "25.0" @@ -34309,97 +34779,97 @@ { "tier": 3.0, "currency": "USDT", - "minNotional": 25000.0, - "maxNotional": 80000.0, + "minNotional": 50000.0, + "maxNotional": 200000.0, "maintenanceMarginRate": 0.025, "maxLeverage": 20.0, "info": { "bracket": "3", "initialLeverage": "20", - "notionalCap": "80000", - "notionalFloor": "25000", + "notionalCap": "200000", + "notionalFloor": "50000", "maintMarginRatio": "0.025", - "cum": "150.0" + "cum": "275.0" } }, { "tier": 4.0, "currency": "USDT", - "minNotional": 80000.0, - "maxNotional": 800000.0, + "minNotional": 200000.0, + "maxNotional": 2000000.0, "maintenanceMarginRate": 0.05, "maxLeverage": 10.0, "info": { "bracket": "4", "initialLeverage": "10", - "notionalCap": "800000", - "notionalFloor": "80000", + "notionalCap": "2000000", + "notionalFloor": "200000", "maintMarginRatio": "0.05", - "cum": "2150.0" + "cum": "5275.0" } }, { "tier": 5.0, "currency": "USDT", - "minNotional": 800000.0, - "maxNotional": 1600000.0, + "minNotional": 2000000.0, + "maxNotional": 4000000.0, "maintenanceMarginRate": 0.1, "maxLeverage": 5.0, "info": { "bracket": "5", "initialLeverage": "5", - "notionalCap": "1600000", - "notionalFloor": "800000", + "notionalCap": "4000000", + "notionalFloor": "2000000", "maintMarginRatio": "0.1", - "cum": "42150.0" + "cum": "105275.0" } }, { "tier": 6.0, "currency": "USDT", - "minNotional": 1600000.0, - "maxNotional": 2000000.0, + "minNotional": 4000000.0, + "maxNotional": 5000000.0, "maintenanceMarginRate": 0.125, "maxLeverage": 4.0, "info": { "bracket": "6", "initialLeverage": "4", - "notionalCap": "2000000", - "notionalFloor": "1600000", + "notionalCap": "5000000", + "notionalFloor": "4000000", "maintMarginRatio": "0.125", - "cum": "82150.0" + "cum": "205275.0" } }, { "tier": 7.0, "currency": "USDT", - "minNotional": 2000000.0, - "maxNotional": 4000000.0, + "minNotional": 5000000.0, + "maxNotional": 10000000.0, "maintenanceMarginRate": 0.25, "maxLeverage": 2.0, "info": { "bracket": "7", "initialLeverage": "2", - "notionalCap": "4000000", - "notionalFloor": "2000000", + "notionalCap": "10000000", + "notionalFloor": "5000000", "maintMarginRatio": "0.25", - "cum": "332150.0" + "cum": "830275.0" } }, { "tier": 8.0, "currency": "USDT", - "minNotional": 4000000.0, - "maxNotional": 8000000.0, + "minNotional": 10000000.0, + "maxNotional": 20000000.0, "maintenanceMarginRate": 0.5, "maxLeverage": 1.0, "info": { "bracket": "8", "initialLeverage": "1", - "notionalCap": "8000000", - "notionalFloor": "4000000", + "notionalCap": "20000000", + "notionalFloor": "10000000", "maintMarginRatio": "0.5", - "cum": "1332150.0" + "cum": "3330275.0" } } ], From 5f1ab7508fe34bf6e7b30ca9149db593050f1426 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 24 Apr 2024 20:39:01 +0200 Subject: [PATCH 05/15] Add idex subclass defining the applicable ohlcv limit --- freqtrade/exchange/__init__.py | 1 + freqtrade/exchange/idex.py | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 freqtrade/exchange/idex.py diff --git a/freqtrade/exchange/__init__.py b/freqtrade/exchange/__init__.py index 8826b70b5..109f3c1e8 100644 --- a/freqtrade/exchange/__init__.py +++ b/freqtrade/exchange/__init__.py @@ -25,6 +25,7 @@ from freqtrade.exchange.exchange_utils_timeframe import (timeframe_to_minutes, t from freqtrade.exchange.gate import Gate from freqtrade.exchange.hitbtc import Hitbtc from freqtrade.exchange.htx import Htx +from freqtrade.exchange.idex import Idex from freqtrade.exchange.kraken import Kraken from freqtrade.exchange.kucoin import Kucoin from freqtrade.exchange.okx import Okx diff --git a/freqtrade/exchange/idex.py b/freqtrade/exchange/idex.py new file mode 100644 index 000000000..eae5ad155 --- /dev/null +++ b/freqtrade/exchange/idex.py @@ -0,0 +1,19 @@ +""" Idex exchange subclass """ +import logging +from typing import Dict + +from freqtrade.exchange import Exchange + + +logger = logging.getLogger(__name__) + + +class Idex(Exchange): + """ + Idex exchange class. Contains adjustments needed for Freqtrade to work + with this exchange. + """ + + _ft_has: Dict = { + "ohlcv_candle_limit": 1000, + } From d6dcd8adca9adedcc78e13f8a3dea0ae6c5cf9bc Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 25 Apr 2024 08:18:17 +0200 Subject: [PATCH 06/15] use explicit macos version macos-latest changed to align to macos-14 - so it's no longer capable of running python 3.9 --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92f8e71c2..1a87b86cf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -129,7 +129,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ "macos-latest", "macos-13", "macos-14" ] + os: [ "macos-12", "macos-13", "macos-14" ] python-version: ["3.9", "3.10", "3.11", "3.12"] exclude: - os: "macos-14" From 3ca0be75435ffcfd819ebcf507801efb1fa2fda5 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 25 Apr 2024 10:26:33 +0200 Subject: [PATCH 07/15] Fix misspelled coingecko variable --- freqtrade/plugins/pairlist/MarketCapPairList.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/freqtrade/plugins/pairlist/MarketCapPairList.py b/freqtrade/plugins/pairlist/MarketCapPairList.py index a618f72d2..0c968f988 100644 --- a/freqtrade/plugins/pairlist/MarketCapPairList.py +++ b/freqtrade/plugins/pairlist/MarketCapPairList.py @@ -38,7 +38,7 @@ class MarketCapPairList(IPairList): self._refresh_period = self._pairlistconfig.get('refresh_period', 86400) self._marketcap_cache: TTLCache = TTLCache(maxsize=1, ttl=self._refresh_period) self._def_candletype = self._config['candle_type_def'] - self._coingekko: CoinGeckoAPI = CoinGeckoAPI() + self._coingecko: CoinGeckoAPI = CoinGeckoAPI() if self._max_rank > 250: raise OperationalException( @@ -127,7 +127,7 @@ class MarketCapPairList(IPairList): marketcap_list = self._marketcap_cache.get('marketcap') if marketcap_list is None: - data = self._coingekko.get_coins_markets(vs_currency='usd', order='market_cap_desc', + data = self._coingecko.get_coins_markets(vs_currency='usd', order='market_cap_desc', per_page='250', page='1', sparkline='false', locale='en') if data: From 2d9be6c8183cf395a17878bf9603554962d3adc6 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 25 Apr 2024 10:27:16 +0200 Subject: [PATCH 08/15] Fix some coingecko spellings --- freqtrade/rpc/fiat_convert.py | 10 +++++----- tests/conftest.py | 6 +++--- tests/rpc/test_fiat_convert.py | 10 +++++----- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/freqtrade/rpc/fiat_convert.py b/freqtrade/rpc/fiat_convert.py index d01596cfc..ec366f0c0 100644 --- a/freqtrade/rpc/fiat_convert.py +++ b/freqtrade/rpc/fiat_convert.py @@ -39,7 +39,7 @@ class CryptoToFiatConverter(LoggingMixin): This object is also a Singleton """ __instance = None - _coingekko: CoinGeckoAPI = None + _coingecko: CoinGeckoAPI = None _coinlistings: List[Dict] = [] _backoff: float = 0.0 @@ -52,9 +52,9 @@ class CryptoToFiatConverter(LoggingMixin): try: # Limit retires to 1 (0 and 1) # otherwise we risk bot impact if coingecko is down. - CryptoToFiatConverter._coingekko = CoinGeckoAPI(retries=1) + CryptoToFiatConverter._coingecko = CoinGeckoAPI(retries=1) except BaseException: - CryptoToFiatConverter._coingekko = None + CryptoToFiatConverter._coingecko = None return CryptoToFiatConverter.__instance def __init__(self) -> None: @@ -67,7 +67,7 @@ class CryptoToFiatConverter(LoggingMixin): def _load_cryptomap(self) -> None: try: # Use list-comprehension to ensure we get a list. - self._coinlistings = [x for x in self._coingekko.get_coins_list()] + self._coinlistings = [x for x in self._coingecko.get_coins_list()] except RequestException as request_exception: if "429" in str(request_exception): logger.warning( @@ -191,7 +191,7 @@ class CryptoToFiatConverter(LoggingMixin): try: return float( - self._coingekko.get_price( + self._coingecko.get_price( ids=_gekko_id, vs_currencies=fiat_symbol )[_gekko_id][fiat_symbol] diff --git a/tests/conftest.py b/tests/conftest.py index 2f6ccc197..b46f30f8f 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -490,10 +490,10 @@ def user_dir(mocker, tmp_path) -> Path: @pytest.fixture(autouse=True) -def patch_coingekko(mocker) -> None: +def patch_coingecko(mocker) -> None: """ - Mocker to coingekko to speed up tests - :param mocker: mocker to patch coingekko class + Mocker to coingecko to speed up tests + :param mocker: mocker to patch coingecko class :return: None """ diff --git a/tests/rpc/test_fiat_convert.py b/tests/rpc/test_fiat_convert.py index 0dfa20185..68b87498e 100644 --- a/tests/rpc/test_fiat_convert.py +++ b/tests/rpc/test_fiat_convert.py @@ -109,16 +109,16 @@ def test_fiat_init_network_exception(mocker): def test_fiat_convert_without_network(mocker): - # Because CryptoToFiatConverter is a Singleton we reset the value of _coingekko + # Because CryptoToFiatConverter is a Singleton we reset the value of _coingecko fiat_convert = CryptoToFiatConverter() - cmc_temp = CryptoToFiatConverter._coingekko - CryptoToFiatConverter._coingekko = None + cmc_temp = CryptoToFiatConverter._coingecko + CryptoToFiatConverter._coingecko = None - assert fiat_convert._coingekko is None + assert fiat_convert._coingecko is None assert fiat_convert._find_price(crypto_symbol='btc', fiat_symbol='usd') == 0.0 - CryptoToFiatConverter._coingekko = cmc_temp + CryptoToFiatConverter._coingecko = cmc_temp def test_fiat_too_many_requests_response(mocker, caplog): From 96bb4db68efcc786cfb1aa5f6c2db1539c9cbf9c Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 25 Apr 2024 10:28:25 +0200 Subject: [PATCH 09/15] Fix remaining coingecko spellings --- freqtrade/rpc/fiat_convert.py | 10 +++++----- tests/rpc/test_fiat_convert.py | 8 ++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/freqtrade/rpc/fiat_convert.py b/freqtrade/rpc/fiat_convert.py index ec366f0c0..2b44d0546 100644 --- a/freqtrade/rpc/fiat_convert.py +++ b/freqtrade/rpc/fiat_convert.py @@ -84,7 +84,7 @@ class CryptoToFiatConverter(LoggingMixin): logger.error( f"Could not load FIAT Cryptocurrency map for the following problem: {exception}") - def _get_gekko_id(self, crypto_symbol): + def _get_gecko_id(self, crypto_symbol): if not self._coinlistings: if self._backoff <= datetime.now().timestamp(): self._load_cryptomap() @@ -180,9 +180,9 @@ class CryptoToFiatConverter(LoggingMixin): if crypto_symbol == fiat_symbol: return 1.0 - _gekko_id = self._get_gekko_id(crypto_symbol) + _gecko_id = self._get_gecko_id(crypto_symbol) - if not _gekko_id: + if not _gecko_id: # return 0 for unsupported stake currencies (fiat-convert should not break the bot) self.log_once( f"unsupported crypto-symbol {crypto_symbol.upper()} - returning 0.0", @@ -192,9 +192,9 @@ class CryptoToFiatConverter(LoggingMixin): try: return float( self._coingecko.get_price( - ids=_gekko_id, + ids=_gecko_id, vs_currencies=fiat_symbol - )[_gekko_id][fiat_symbol] + )[_gecko_id][fiat_symbol] ) except Exception as exception: logger.error("Error in _find_price: %s", exception) diff --git a/tests/rpc/test_fiat_convert.py b/tests/rpc/test_fiat_convert.py index 68b87498e..717866cfd 100644 --- a/tests/rpc/test_fiat_convert.py +++ b/tests/rpc/test_fiat_convert.py @@ -90,7 +90,7 @@ def test_loadcryptomap(mocker): fiat_convert = CryptoToFiatConverter() assert len(fiat_convert._coinlistings) == 2 - assert fiat_convert._get_gekko_id("btc") == "bitcoin" + assert fiat_convert._get_gecko_id("btc") == "bitcoin" def test_fiat_init_network_exception(mocker): @@ -152,9 +152,9 @@ def test_fiat_multiple_coins(mocker, caplog): {'id': 'ethereum-wormhole', 'symbol': 'eth', 'name': 'Ethereum Wormhole'}, ] - assert fiat_convert._get_gekko_id('btc') == 'bitcoin' - assert fiat_convert._get_gekko_id('hnt') is None - assert fiat_convert._get_gekko_id('eth') == 'ethereum' + assert fiat_convert._get_gecko_id('btc') == 'bitcoin' + assert fiat_convert._get_gecko_id('hnt') is None + assert fiat_convert._get_gecko_id('eth') == 'ethereum' assert log_has('Found multiple mappings in CoinGecko for hnt.', caplog) From ad12c98d10021bace86679546090014bdacbce21 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 25 Apr 2024 10:42:55 +0200 Subject: [PATCH 10/15] Avoid having test-result influence from user_data/ this avoids potential deprecation warnings (or even errors) caused by strategies in user_data/strategies --- tests/optimize/test_hyperopt_tools.py | 5 +++-- tests/optimize/test_recursive_analysis.py | 3 ++- tests/rpc/test_rpc_apiserver.py | 3 ++- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/optimize/test_hyperopt_tools.py b/tests/optimize/test_hyperopt_tools.py index c46897374..47aba6b76 100644 --- a/tests/optimize/test_hyperopt_tools.py +++ b/tests/optimize/test_hyperopt_tools.py @@ -172,8 +172,8 @@ def test__pprint_dict(): }""" -def test_get_strategy_filename(default_conf): - +def test_get_strategy_filename(default_conf, tmp_path): + default_conf['user_data_dir'] = tmp_path x = HyperoptTools.get_strategy_filename(default_conf, 'StrategyTestV3') assert isinstance(x, Path) assert x == Path(__file__).parents[1] / 'strategy/strats/strategy_test_v3.py' @@ -233,6 +233,7 @@ def test_export_params(tmp_path): def test_try_export_params(default_conf, tmp_path, caplog, mocker): default_conf['disableparamexport'] = False + default_conf['user_data_dir'] = tmp_path export_mock = mocker.patch("freqtrade.optimize.hyperopt_tools.HyperoptTools.export_params") filename = tmp_path / f"{CURRENT_TEST_STRATEGY}.json" diff --git a/tests/optimize/test_recursive_analysis.py b/tests/optimize/test_recursive_analysis.py index 33fae0d08..95a96c9f5 100644 --- a/tests/optimize/test_recursive_analysis.py +++ b/tests/optimize/test_recursive_analysis.py @@ -14,7 +14,8 @@ from tests.conftest import get_args, log_has_re, patch_exchange @pytest.fixture -def recursive_conf(default_conf_usdt): +def recursive_conf(default_conf_usdt, tmp_path): + default_conf_usdt['user_data_dir'] = tmp_path default_conf_usdt['timerange'] = '20220101-20220501' default_conf_usdt['strategy_path'] = str( diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 7259dfb9a..7281686ea 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -1648,8 +1648,9 @@ def test_api_pair_history(botclient, mocker): assert rc.json()['detail'] == ("No data for UNITTEST/BTC, 5m in 20200111-20200112 found.") -def test_api_plot_config(botclient, mocker): +def test_api_plot_config(botclient, mocker, tmp_path): ftbot, client = botclient + ftbot.config['user_data_dir'] = tmp_path rc = client_get(client, f"{BASE_URI}/plot_config") assert_response(rc) From 35408966f47b81be6f4fa3d7c7c5211ac4a6ad40 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 25 Apr 2024 11:02:34 +0200 Subject: [PATCH 11/15] Fix remaining user_data leaks --- tests/optimize/test_lookahead_analysis.py | 3 ++- tests/rpc/test_rpc_apiserver.py | 7 +++++-- tests/strategy/test_strategy_loading.py | 7 +++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/tests/optimize/test_lookahead_analysis.py b/tests/optimize/test_lookahead_analysis.py index 14840428d..6c84663b6 100644 --- a/tests/optimize/test_lookahead_analysis.py +++ b/tests/optimize/test_lookahead_analysis.py @@ -14,7 +14,8 @@ from tests.conftest import EXMS, get_args, log_has_re, patch_exchange @pytest.fixture -def lookahead_conf(default_conf_usdt): +def lookahead_conf(default_conf_usdt, tmp_path): + default_conf_usdt['user_data_dir'] = tmp_path default_conf_usdt['minimum_trade_amount'] = 10 default_conf_usdt['targeted_trade_amount'] = 20 default_conf_usdt['timerange'] = '20220101-20220501' diff --git a/tests/rpc/test_rpc_apiserver.py b/tests/rpc/test_rpc_apiserver.py index 7281686ea..5b189371a 100644 --- a/tests/rpc/test_rpc_apiserver.py +++ b/tests/rpc/test_rpc_apiserver.py @@ -1577,8 +1577,10 @@ def test_api_pair_candles(botclient, ohlcv_history): ]) -def test_api_pair_history(botclient, mocker): +def test_api_pair_history(botclient, tmp_path, mocker): _ftbot, client = botclient + _ftbot.config['user_data_dir'] = tmp_path + timeframe = '5m' lfm = mocker.patch('freqtrade.strategy.interface.IStrategy.load_freqAI_model') # No pair @@ -1718,8 +1720,9 @@ def test_api_strategies(botclient, tmp_path): ]} -def test_api_strategy(botclient): +def test_api_strategy(botclient, tmp_path): _ftbot, client = botclient + _ftbot.config['user_data_dir'] = tmp_path rc = client_get(client, f"{BASE_URI}/strategy/{CURRENT_TEST_STRATEGY}") diff --git a/tests/strategy/test_strategy_loading.py b/tests/strategy/test_strategy_loading.py index a31408b5c..33245cc5f 100644 --- a/tests/strategy/test_strategy_loading.py +++ b/tests/strategy/test_strategy_loading.py @@ -78,7 +78,9 @@ def test_load_strategy_base64(dataframe_1m, caplog, default_conf): r".*(/|\\).*(/|\\)SampleStrategy\.py'\.\.\.", caplog) -def test_load_strategy_invalid_directory(caplog, default_conf): +def test_load_strategy_invalid_directory(caplog, default_conf, tmp_path): + default_conf['user_data_dir'] = tmp_path + extra_dir = Path.cwd() / 'some/path' with pytest.raises(OperationalException, match=r"Impossible to load Strategy.*"): StrategyResolver._load_strategy('StrategyTestV333', config=default_conf, @@ -87,7 +89,8 @@ def test_load_strategy_invalid_directory(caplog, default_conf): assert log_has_re(r'Path .*' + r'some.*path.*' + r'.* does not exist', caplog) -def test_load_not_found_strategy(default_conf): +def test_load_not_found_strategy(default_conf, tmp_path): + default_conf['user_data_dir'] = tmp_path default_conf['strategy'] = 'NotFoundStrategy' with pytest.raises(OperationalException, match=r"Impossible to load Strategy 'NotFoundStrategy'. " From 0a89efd002db549ffe45d91e519b910d9fb69619 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 25 Apr 2024 11:43:24 +0200 Subject: [PATCH 12/15] Only cancel stoploss if really necessary partial workaround for #10002 --- freqtrade/freqtradebot.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index d24732e12..a7e35838b 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -462,6 +462,7 @@ class FreqtradeBot(LoggingMixin): trade.pair, trade.open_date_utc - timedelta(seconds=10)) prev_exit_reason = trade.exit_reason prev_trade_state = trade.is_open + prev_trade_amount = trade.amount for order in orders: trade_order = [o for o in trade.orders if o.order_id == order['id']] @@ -493,6 +494,10 @@ class FreqtradeBot(LoggingMixin): send_msg=prev_trade_state != trade.is_open) else: trade.exit_reason = prev_exit_reason + + if prev_trade_amount != trade.amount: + # Cancel stoploss on exchange if the amount changed + trade = self.cancel_stoploss_on_exchange(trade) Trade.commit() except ExchangeError: @@ -1948,21 +1953,23 @@ class FreqtradeBot(LoggingMixin): trade.update_trade(order_obj, not send_msg) - trade = self._update_trade_after_fill(trade, order_obj) + trade = self._update_trade_after_fill(trade, order_obj, send_msg) Trade.commit() self.order_close_notify(trade, order_obj, stoploss_order, send_msg) return False - def _update_trade_after_fill(self, trade: Trade, order: Order) -> Trade: + def _update_trade_after_fill(self, trade: Trade, order: Order, send_msg: bool) -> Trade: if order.status in constants.NON_OPEN_EXCHANGE_STATES: strategy_safe_wrapper( self.strategy.order_filled, default_retval=None)( pair=trade.pair, trade=trade, order=order, current_time=datetime.now(timezone.utc)) # If a entry order was closed, force update on stoploss on exchange if order.ft_order_side == trade.entry_side: - trade = self.cancel_stoploss_on_exchange(trade) + if send_msg: + # Don't cancel stoploss in recovery modes immediately + trade = self.cancel_stoploss_on_exchange(trade) if not self.edge: # TODO: should shorting/leverage be supported by Edge, # then this will need to be fixed. From adbf1b5e6f3db17d082efdfdc45fa8fab2d96b05 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 25 Apr 2024 11:46:43 +0200 Subject: [PATCH 13/15] Adjust trade amount by 2% if trade recovery remains above the trade amount closes #10002 --- freqtrade/freqtradebot.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index a7e35838b..244095ca7 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -494,7 +494,23 @@ class FreqtradeBot(LoggingMixin): send_msg=prev_trade_state != trade.is_open) else: trade.exit_reason = prev_exit_reason - + total = self.wallets.get_total(trade.base_currency) + if total < trade.amount: + if total > trade.amount * 0.98: + logger.warning( + f"{trade} has a total of {trade.amount} {trade.base_currency}, " + f"but the Wallet shows a total of {total} {trade.base_currency}. " + f"Adjusting trade amount to {total}." + "This may however lead to further issues." + ) + trade.amount = total + else: + logger.warning( + f"{trade} has a total of {trade.amount} {trade.base_currency}, " + f"but the Wallet shows a total of {total} {trade.base_currency}. " + "Refusing to adjust as the difference is too large." + "This may however lead to further issues." + ) if prev_trade_amount != trade.amount: # Cancel stoploss on exchange if the amount changed trade = self.cancel_stoploss_on_exchange(trade) From a3e6abef8dc58bef3e54dd12522cbdadcae714de Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 25 Apr 2024 13:38:37 +0200 Subject: [PATCH 14/15] Add test for "trade amount adjust" behavior --- tests/freqtradebot/test_freqtradebot.py | 61 +++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/tests/freqtradebot/test_freqtradebot.py b/tests/freqtradebot/test_freqtradebot.py index e46caa8b2..993091068 100644 --- a/tests/freqtradebot/test_freqtradebot.py +++ b/tests/freqtradebot/test_freqtradebot.py @@ -4558,6 +4558,67 @@ def test_handle_onexchange_order(mocker, default_conf_usdt, limit_order, is_shor assert trade.exit_reason == ExitType.SOLD_ON_EXCHANGE.value +@pytest.mark.usefixtures("init_persistence") +@pytest.mark.parametrize("is_short", [False, True]) +@pytest.mark.parametrize("factor,adjusts", [ + (0.99, True), + (0.97, False), +]) +def test_handle_onexchange_order_changed_amount( + mocker, default_conf_usdt, limit_order, is_short, caplog, + factor, adjusts, +): + default_conf_usdt['dry_run'] = False + freqtrade = get_patched_freqtradebot(mocker, default_conf_usdt) + mock_uts = mocker.spy(freqtrade, 'update_trade_state') + + entry_order = limit_order[entry_side(is_short)] + mock_fo = mocker.patch(f'{EXMS}.fetch_orders', return_value=[ + entry_order, + ]) + + trade = Trade( + pair='ETH/USDT', + fee_open=0.001, + base_currency='ETH', + fee_close=0.001, + open_rate=entry_order['price'], + open_date=dt_now(), + stake_amount=entry_order['cost'], + amount=entry_order['amount'], + exchange="binance", + is_short=is_short, + leverage=1, + ) + freqtrade.wallets = MagicMock() + freqtrade.wallets.get_total = MagicMock(return_value=entry_order['amount'] * factor) + + trade.orders.append(Order.parse_from_ccxt_object( + entry_order, 'ADA/USDT', entry_side(is_short)) + ) + Trade.session.add(trade) + + # assert trade.amount > entry_order['amount'] + + freqtrade.handle_onexchange_order(trade) + assert mock_uts.call_count == 1 + assert mock_fo.call_count == 1 + + trade = Trade.session.scalars(select(Trade)).first() + + assert log_has_re(r'.*has a total of .* but the Wallet shows.*', caplog) + if adjusts: + # Trade amount is updated + assert trade.amount == entry_order['amount'] * factor + assert log_has_re(r'.*Adjusting trade amount to.*', caplog) + else: + assert log_has_re(r'.*Refusing to adjust as the difference.*', caplog) + assert trade.amount == entry_order['amount'] + + assert len(trade.orders) == 1 + assert trade.is_open is True + + @pytest.mark.usefixtures("init_persistence") @pytest.mark.parametrize("is_short", [False, True]) def test_handle_onexchange_order_exit(mocker, default_conf_usdt, limit_order, is_short, caplog): From 8e5c574224cf55a308e8bf71ff1af4faf5cc5fee Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 25 Apr 2024 19:56:27 +0200 Subject: [PATCH 15/15] Don't handle case where base_currency is not set (very old trades) --- freqtrade/freqtradebot.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/freqtradebot.py b/freqtrade/freqtradebot.py index 244095ca7..aa233c3ff 100644 --- a/freqtrade/freqtradebot.py +++ b/freqtrade/freqtradebot.py @@ -494,7 +494,7 @@ class FreqtradeBot(LoggingMixin): send_msg=prev_trade_state != trade.is_open) else: trade.exit_reason = prev_exit_reason - total = self.wallets.get_total(trade.base_currency) + total = self.wallets.get_total(trade.base_currency) if trade.base_currency else 0 if total < trade.amount: if total > trade.amount * 0.98: logger.warning(