We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Docker container as non root user
The current docker container uses root user by default. This caused permission problems from the host side. For example, I can't edit files from binded folders without sudo. 

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `freqtrade/commands/build_config_commands.py`
Content:
```
1 import logging
2 import secrets
3 from pathlib import Path
4 from typing import Any, Dict, List
5 
6 from questionary import Separator, prompt
7 
8 from freqtrade.constants import UNLIMITED_STAKE_AMOUNT
9 from freqtrade.exceptions import OperationalException
10 from freqtrade.exchange import MAP_EXCHANGE_CHILDCLASS, available_exchanges
11 from freqtrade.misc import render_template
12 
13 
14 logger = logging.getLogger(__name__)
15 
16 
17 def validate_is_int(val):
18     try:
19         _ = int(val)
20         return True
21     except Exception:
22         return False
23 
24 
25 def validate_is_float(val):
26     try:
27         _ = float(val)
28         return True
29     except Exception:
30         return False
31 
32 
33 def ask_user_overwrite(config_path: Path) -> bool:
34     questions = [
35         {
36             "type": "confirm",
37             "name": "overwrite",
38             "message": f"File {config_path} already exists. Overwrite?",
39             "default": False,
40         },
41     ]
42     answers = prompt(questions)
43     return answers['overwrite']
44 
45 
46 def ask_user_config() -> Dict[str, Any]:
47     """
48     Ask user a few questions to build the configuration.
49     Interactive questions built using https://github.com/tmbo/questionary
50     :returns: Dict with keys to put into template
51     """
52     questions: List[Dict[str, Any]] = [
53         {
54             "type": "confirm",
55             "name": "dry_run",
56             "message": "Do you want to enable Dry-run (simulated trades)?",
57             "default": True,
58         },
59         {
60             "type": "text",
61             "name": "stake_currency",
62             "message": "Please insert your stake currency:",
63             "default": 'BTC',
64         },
65         {
66             "type": "text",
67             "name": "stake_amount",
68             "message": "Please insert your stake amount:",
69             "default": "0.01",
70             "validate": lambda val: val == UNLIMITED_STAKE_AMOUNT or validate_is_float(val),
71         },
72         {
73             "type": "text",
74             "name": "max_open_trades",
75             "message": f"Please insert max_open_trades (Integer or '{UNLIMITED_STAKE_AMOUNT}'):",
76             "default": "3",
77             "validate": lambda val: val == UNLIMITED_STAKE_AMOUNT or validate_is_int(val)
78         },
79         {
80             "type": "text",
81             "name": "timeframe",
82             "message": "Please insert your desired timeframe (e.g. 5m):",
83             "default": "5m",
84         },
85         {
86             "type": "text",
87             "name": "fiat_display_currency",
88             "message": "Please insert your display Currency (for reporting):",
89             "default": 'USD',
90         },
91         {
92             "type": "select",
93             "name": "exchange_name",
94             "message": "Select exchange",
95             "choices": [
96                 "binance",
97                 "binanceus",
98                 "bittrex",
99                 "kraken",
100                 "ftx",
101                 Separator(),
102                 "other",
103             ],
104         },
105         {
106             "type": "autocomplete",
107             "name": "exchange_name",
108             "message": "Type your exchange name (Must be supported by ccxt)",
109             "choices": available_exchanges(),
110             "when": lambda x: x["exchange_name"] == 'other'
111         },
112         {
113             "type": "password",
114             "name": "exchange_key",
115             "message": "Insert Exchange Key",
116             "when": lambda x: not x['dry_run']
117         },
118         {
119             "type": "password",
120             "name": "exchange_secret",
121             "message": "Insert Exchange Secret",
122             "when": lambda x: not x['dry_run']
123         },
124         {
125             "type": "confirm",
126             "name": "telegram",
127             "message": "Do you want to enable Telegram?",
128             "default": False,
129         },
130         {
131             "type": "password",
132             "name": "telegram_token",
133             "message": "Insert Telegram token",
134             "when": lambda x: x['telegram']
135         },
136         {
137             "type": "text",
138             "name": "telegram_chat_id",
139             "message": "Insert Telegram chat id",
140             "when": lambda x: x['telegram']
141         },
142         {
143             "type": "confirm",
144             "name": "api_server",
145             "message": "Do you want to enable the Rest API (includes FreqUI)?",
146             "default": False,
147         },
148         {
149             "type": "text",
150             "name": "api_server_listen_addr",
151             "message": "Insert Api server Listen Address (best left untouched default!)",
152             "default": "127.0.0.1",
153             "when": lambda x: x['api_server']
154         },
155         {
156             "type": "text",
157             "name": "api_server_username",
158             "message": "Insert api-server username",
159             "default": "freqtrader",
160             "when": lambda x: x['api_server']
161         },
162         {
163             "type": "text",
164             "name": "api_server_password",
165             "message": "Insert api-server password",
166             "when": lambda x: x['api_server']
167         },
168     ]
169     answers = prompt(questions)
170 
171     if not answers:
172         # Interrupted questionary sessions return an empty dict.
173         raise OperationalException("User interrupted interactive questions.")
174 
175     # Force JWT token to be a random string
176     answers['api_server_jwt_key'] = secrets.token_hex()
177 
178     return answers
179 
180 
181 def deploy_new_config(config_path: Path, selections: Dict[str, Any]) -> None:
182     """
183     Applies selections to the template and writes the result to config_path
184     :param config_path: Path object for new config file. Should not exist yet
185     :param selecions: Dict containing selections taken by the user.
186     """
187     from jinja2.exceptions import TemplateNotFound
188     try:
189         exchange_template = MAP_EXCHANGE_CHILDCLASS.get(
190             selections['exchange_name'], selections['exchange_name'])
191 
192         selections['exchange'] = render_template(
193             templatefile=f"subtemplates/exchange_{exchange_template}.j2",
194             arguments=selections
195             )
196     except TemplateNotFound:
197         selections['exchange'] = render_template(
198             templatefile="subtemplates/exchange_generic.j2",
199             arguments=selections
200         )
201 
202     config_text = render_template(templatefile='base_config.json.j2',
203                                   arguments=selections)
204 
205     logger.info(f"Writing config to `{config_path}`.")
206     logger.info(
207         "Please make sure to check the configuration contents and adjust settings to your needs.")
208 
209     config_path.write_text(config_text)
210 
211 
212 def start_new_config(args: Dict[str, Any]) -> None:
213     """
214     Create a new strategy from a template
215     Asking the user questions to fill out the templateaccordingly.
216     """
217 
218     config_path = Path(args['config'][0])
219     if config_path.exists():
220         overwrite = ask_user_overwrite(config_path)
221         if overwrite:
222             config_path.unlink()
223         else:
224             raise OperationalException(
225                 f"Configuration file `{config_path}` already exists. "
226                 "Please delete it or use a different configuration file name.")
227     selections = ask_user_config()
228     deploy_new_config(config_path, selections)
229
```

Path: `freqtrade/configuration/directory_operations.py`
Content:
```
1 import logging
2 import shutil
3 from pathlib import Path
4 from typing import Any, Dict, Optional
5 
6 from freqtrade.constants import USER_DATA_FILES
7 from freqtrade.exceptions import OperationalException
8 
9 
10 logger = logging.getLogger(__name__)
11 
12 
13 def create_datadir(config: Dict[str, Any], datadir: Optional[str] = None) -> Path:
14 
15     folder = Path(datadir) if datadir else Path(f"{config['user_data_dir']}/data")
16     if not datadir:
17         # set datadir
18         exchange_name = config.get('exchange', {}).get('name').lower()
19         folder = folder.joinpath(exchange_name)
20 
21     if not folder.is_dir():
22         folder.mkdir(parents=True)
23         logger.info(f'Created data directory: {datadir}')
24     return folder
25 
26 
27 def create_userdata_dir(directory: str, create_dir: bool = False) -> Path:
28     """
29     Create userdata directory structure.
30     if create_dir is True, then the parent-directory will be created if it does not exist.
31     Sub-directories will always be created if the parent directory exists.
32     Raises OperationalException if given a non-existing directory.
33     :param directory: Directory to check
34     :param create_dir: Create directory if it does not exist.
35     :return: Path object containing the directory
36     """
37     sub_dirs = ["backtest_results", "data", "hyperopts", "hyperopt_results", "logs",
38                 "notebooks", "plot", "strategies", ]
39     folder = Path(directory)
40     if not folder.is_dir():
41         if create_dir:
42             folder.mkdir(parents=True)
43             logger.info(f'Created user-data directory: {folder}')
44         else:
45             raise OperationalException(
46                 f"Directory `{folder}` does not exist. "
47                 "Please use `freqtrade create-userdir` to create a user directory")
48 
49     # Create required subdirectories
50     for f in sub_dirs:
51         subfolder = folder / f
52         if not subfolder.is_dir():
53             subfolder.mkdir(parents=False)
54     return folder
55 
56 
57 def copy_sample_files(directory: Path, overwrite: bool = False) -> None:
58     """
59     Copy files from templates to User data directory.
60     :param directory: Directory to copy data to
61     :param overwrite: Overwrite existing sample files
62     """
63     if not directory.is_dir():
64         raise OperationalException(f"Directory `{directory}` does not exist.")
65     sourcedir = Path(__file__).parents[1] / "templates"
66     for source, target in USER_DATA_FILES.items():
67         targetdir = directory / target
68         if not targetdir.is_dir():
69             raise OperationalException(f"Directory `{targetdir}` does not exist.")
70         targetfile = targetdir / source
71         if targetfile.exists():
72             if not overwrite:
73                 logger.warning(f"File `{targetfile}` exists already, not deploying sample file.")
74                 continue
75             logger.warning(f"File `{targetfile}` exists already, overwriting.")
76         shutil.copy(str(sourcedir / source), str(targetfile))
77
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py
--- a/freqtrade/commands/build_config_commands.py
+++ b/freqtrade/commands/build_config_commands.py
@@ -5,6 +5,7 @@
 
 from questionary import Separator, prompt
 
+from freqtrade.configuration.directory_operations import chown_user_directory
 from freqtrade.constants import UNLIMITED_STAKE_AMOUNT
 from freqtrade.exceptions import OperationalException
 from freqtrade.exchange import MAP_EXCHANGE_CHILDCLASS, available_exchanges
@@ -216,6 +217,7 @@
     """
 
     config_path = Path(args['config'][0])
+    chown_user_directory(config_path.parent)
     if config_path.exists():
         overwrite = ask_user_overwrite(config_path)
         if overwrite:
diff --git a/freqtrade/configuration/directory_operations.py b/freqtrade/configuration/directory_operations.py
--- a/freqtrade/configuration/directory_operations.py
+++ b/freqtrade/configuration/directory_operations.py
@@ -24,6 +24,21 @@
     return folder
 
 
+def chown_user_directory(directory: Path) -> None:
+    """
+    Use Sudo to change permissions of the home-directory if necessary
+    Only applies when running in docker!
+    """
+    import os
+    if os.environ.get('FT_APP_ENV') == 'docker':
+        try:
+            import subprocess
+            subprocess.check_output(
+                ['sudo', 'chown', '-R', 'ftuser:', str(directory.resolve())])
+        except Exception:
+            logger.warning(f"Could not chown {directory}")
+
+
 def create_userdata_dir(directory: str, create_dir: bool = False) -> Path:
     """
     Create userdata directory structure.
@@ -37,6 +52,7 @@
     sub_dirs = ["backtest_results", "data", "hyperopts", "hyperopt_results", "logs",
                 "notebooks", "plot", "strategies", ]
     folder = Path(directory)
+    chown_user_directory(folder)
     if not folder.is_dir():
         if create_dir:
             folder.mkdir(parents=True)

{"golden_diff": "diff --git a/freqtrade/commands/build_config_commands.py b/freqtrade/commands/build_config_commands.py\n--- a/freqtrade/commands/build_config_commands.py\n+++ b/freqtrade/commands/build_config_commands.py\n@@ -5,6 +5,7 @@\n \n from questionary import Separator, prompt\n \n+from freqtrade.configuration.directory_operations import chown_user_directory\n from freqtrade.constants import UNLIMITED_STAKE_AMOUNT\n from freqtrade.exceptions import OperationalException\n from freqtrade.exchange import MAP_EXCHANGE_CHILDCLASS, available_exchanges\n@@ -216,6 +217,7 @@\n     \"\"\"\n \n     config_path = Path(args['config'][0])\n+    chown_user_directory(config_path.parent)\n     if config_path.exists():\n         overwrite = ask_user_overwrite(config_path)\n         if overwrite:\ndiff --git a/freqtrade/configuration/directory_operations.py b/freqtrade/configuration/directory_operations.py\n--- a/freqtrade/configuration/directory_operations.py\n+++ b/freqtrade/configuration/directory_operations.py\n@@ -24,6 +24,21 @@\n     return folder\n \n \n+def chown_user_directory(directory: Path) -> None:\n+    \"\"\"\n+    Use Sudo to change permissions of the home-directory if necessary\n+    Only applies when running in docker!\n+    \"\"\"\n+    import os\n+    if os.environ.get('FT_APP_ENV') == 'docker':\n+        try:\n+            import subprocess\n+            subprocess.check_output(\n+                ['sudo', 'chown', '-R', 'ftuser:', str(directory.resolve())])\n+        except Exception:\n+            logger.warning(f\"Could not chown {directory}\")\n+\n+\n def create_userdata_dir(directory: str, create_dir: bool = False) -> Path:\n     \"\"\"\n     Create userdata directory structure.\n@@ -37,6 +52,7 @@\n     sub_dirs = [\"backtest_results\", \"data\", \"hyperopts\", \"hyperopt_results\", \"logs\",\n                 \"notebooks\", \"plot\", \"strategies\", ]\n     folder = Path(directory)\n+    chown_user_directory(folder)\n     if not folder.is_dir():\n         if create_dir:\n             folder.mkdir(parents=True)\n", "issue": "Docker container as non root user\nThe current docker container uses root user by default. This caused permission problems from the host side. For example, I can't edit files from binded folders without sudo. \n", "before_files": [{"content": "import logging\nimport secrets\nfrom pathlib import Path\nfrom typing import Any, Dict, List\n\nfrom questionary import Separator, prompt\n\nfrom freqtrade.constants import UNLIMITED_STAKE_AMOUNT\nfrom freqtrade.exceptions import OperationalException\nfrom freqtrade.exchange import MAP_EXCHANGE_CHILDCLASS, available_exchanges\nfrom freqtrade.misc import render_template\n\n\nlogger = logging.getLogger(__name__)\n\n\ndef validate_is_int(val):\n    try:\n        _ = int(val)\n        return True\n    except Exception:\n        return False\n\n\ndef validate_is_float(val):\n    try:\n        _ = float(val)\n        return True\n    except Exception:\n        return False\n\n\ndef ask_user_overwrite(config_path: Path) -> bool:\n    questions = [\n        {\n            \"type\": \"confirm\",\n            \"name\": \"overwrite\",\n            \"message\": f\"File {config_path} already exists. Overwrite?\",\n            \"default\": False,\n        },\n    ]\n    answers = prompt(questions)\n    return answers['overwrite']\n\n\ndef ask_user_config() -> Dict[str, Any]:\n    \"\"\"\n    Ask user a few questions to build the configuration.\n    Interactive questions built using https://github.com/tmbo/questionary\n    :returns: Dict with keys to put into template\n    \"\"\"\n    questions: List[Dict[str, Any]] = [\n        {\n            \"type\": \"confirm\",\n            \"name\": \"dry_run\",\n            \"message\": \"Do you want to enable Dry-run (simulated trades)?\",\n            \"default\": True,\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"stake_currency\",\n            \"message\": \"Please insert your stake currency:\",\n            \"default\": 'BTC',\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"stake_amount\",\n            \"message\": \"Please insert your stake amount:\",\n            \"default\": \"0.01\",\n            \"validate\": lambda val: val == UNLIMITED_STAKE_AMOUNT or validate_is_float(val),\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"max_open_trades\",\n            \"message\": f\"Please insert max_open_trades (Integer or '{UNLIMITED_STAKE_AMOUNT}'):\",\n            \"default\": \"3\",\n            \"validate\": lambda val: val == UNLIMITED_STAKE_AMOUNT or validate_is_int(val)\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"timeframe\",\n            \"message\": \"Please insert your desired timeframe (e.g. 5m):\",\n            \"default\": \"5m\",\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"fiat_display_currency\",\n            \"message\": \"Please insert your display Currency (for reporting):\",\n            \"default\": 'USD',\n        },\n        {\n            \"type\": \"select\",\n            \"name\": \"exchange_name\",\n            \"message\": \"Select exchange\",\n            \"choices\": [\n                \"binance\",\n                \"binanceus\",\n                \"bittrex\",\n                \"kraken\",\n                \"ftx\",\n                Separator(),\n                \"other\",\n            ],\n        },\n        {\n            \"type\": \"autocomplete\",\n            \"name\": \"exchange_name\",\n            \"message\": \"Type your exchange name (Must be supported by ccxt)\",\n            \"choices\": available_exchanges(),\n            \"when\": lambda x: x[\"exchange_name\"] == 'other'\n        },\n        {\n            \"type\": \"password\",\n            \"name\": \"exchange_key\",\n            \"message\": \"Insert Exchange Key\",\n            \"when\": lambda x: not x['dry_run']\n        },\n        {\n            \"type\": \"password\",\n            \"name\": \"exchange_secret\",\n            \"message\": \"Insert Exchange Secret\",\n            \"when\": lambda x: not x['dry_run']\n        },\n        {\n            \"type\": \"confirm\",\n            \"name\": \"telegram\",\n            \"message\": \"Do you want to enable Telegram?\",\n            \"default\": False,\n        },\n        {\n            \"type\": \"password\",\n            \"name\": \"telegram_token\",\n            \"message\": \"Insert Telegram token\",\n            \"when\": lambda x: x['telegram']\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"telegram_chat_id\",\n            \"message\": \"Insert Telegram chat id\",\n            \"when\": lambda x: x['telegram']\n        },\n        {\n            \"type\": \"confirm\",\n            \"name\": \"api_server\",\n            \"message\": \"Do you want to enable the Rest API (includes FreqUI)?\",\n            \"default\": False,\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"api_server_listen_addr\",\n            \"message\": \"Insert Api server Listen Address (best left untouched default!)\",\n            \"default\": \"127.0.0.1\",\n            \"when\": lambda x: x['api_server']\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"api_server_username\",\n            \"message\": \"Insert api-server username\",\n            \"default\": \"freqtrader\",\n            \"when\": lambda x: x['api_server']\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"api_server_password\",\n            \"message\": \"Insert api-server password\",\n            \"when\": lambda x: x['api_server']\n        },\n    ]\n    answers = prompt(questions)\n\n    if not answers:\n        # Interrupted questionary sessions return an empty dict.\n        raise OperationalException(\"User interrupted interactive questions.\")\n\n    # Force JWT token to be a random string\n    answers['api_server_jwt_key'] = secrets.token_hex()\n\n    return answers\n\n\ndef deploy_new_config(config_path: Path, selections: Dict[str, Any]) -> None:\n    \"\"\"\n    Applies selections to the template and writes the result to config_path\n    :param config_path: Path object for new config file. Should not exist yet\n    :param selecions: Dict containing selections taken by the user.\n    \"\"\"\n    from jinja2.exceptions import TemplateNotFound\n    try:\n        exchange_template = MAP_EXCHANGE_CHILDCLASS.get(\n            selections['exchange_name'], selections['exchange_name'])\n\n        selections['exchange'] = render_template(\n            templatefile=f\"subtemplates/exchange_{exchange_template}.j2\",\n            arguments=selections\n            )\n    except TemplateNotFound:\n        selections['exchange'] = render_template(\n            templatefile=\"subtemplates/exchange_generic.j2\",\n            arguments=selections\n        )\n\n    config_text = render_template(templatefile='base_config.json.j2',\n                                  arguments=selections)\n\n    logger.info(f\"Writing config to `{config_path}`.\")\n    logger.info(\n        \"Please make sure to check the configuration contents and adjust settings to your needs.\")\n\n    config_path.write_text(config_text)\n\n\ndef start_new_config(args: Dict[str, Any]) -> None:\n    \"\"\"\n    Create a new strategy from a template\n    Asking the user questions to fill out the templateaccordingly.\n    \"\"\"\n\n    config_path = Path(args['config'][0])\n    if config_path.exists():\n        overwrite = ask_user_overwrite(config_path)\n        if overwrite:\n            config_path.unlink()\n        else:\n            raise OperationalException(\n                f\"Configuration file `{config_path}` already exists. \"\n                \"Please delete it or use a different configuration file name.\")\n    selections = ask_user_config()\n    deploy_new_config(config_path, selections)\n", "path": "freqtrade/commands/build_config_commands.py"}, {"content": "import logging\nimport shutil\nfrom pathlib import Path\nfrom typing import Any, Dict, Optional\n\nfrom freqtrade.constants import USER_DATA_FILES\nfrom freqtrade.exceptions import OperationalException\n\n\nlogger = logging.getLogger(__name__)\n\n\ndef create_datadir(config: Dict[str, Any], datadir: Optional[str] = None) -> Path:\n\n    folder = Path(datadir) if datadir else Path(f\"{config['user_data_dir']}/data\")\n    if not datadir:\n        # set datadir\n        exchange_name = config.get('exchange', {}).get('name').lower()\n        folder = folder.joinpath(exchange_name)\n\n    if not folder.is_dir():\n        folder.mkdir(parents=True)\n        logger.info(f'Created data directory: {datadir}')\n    return folder\n\n\ndef create_userdata_dir(directory: str, create_dir: bool = False) -> Path:\n    \"\"\"\n    Create userdata directory structure.\n    if create_dir is True, then the parent-directory will be created if it does not exist.\n    Sub-directories will always be created if the parent directory exists.\n    Raises OperationalException if given a non-existing directory.\n    :param directory: Directory to check\n    :param create_dir: Create directory if it does not exist.\n    :return: Path object containing the directory\n    \"\"\"\n    sub_dirs = [\"backtest_results\", \"data\", \"hyperopts\", \"hyperopt_results\", \"logs\",\n                \"notebooks\", \"plot\", \"strategies\", ]\n    folder = Path(directory)\n    if not folder.is_dir():\n        if create_dir:\n            folder.mkdir(parents=True)\n            logger.info(f'Created user-data directory: {folder}')\n        else:\n            raise OperationalException(\n                f\"Directory `{folder}` does not exist. \"\n                \"Please use `freqtrade create-userdir` to create a user directory\")\n\n    # Create required subdirectories\n    for f in sub_dirs:\n        subfolder = folder / f\n        if not subfolder.is_dir():\n            subfolder.mkdir(parents=False)\n    return folder\n\n\ndef copy_sample_files(directory: Path, overwrite: bool = False) -> None:\n    \"\"\"\n    Copy files from templates to User data directory.\n    :param directory: Directory to copy data to\n    :param overwrite: Overwrite existing sample files\n    \"\"\"\n    if not directory.is_dir():\n        raise OperationalException(f\"Directory `{directory}` does not exist.\")\n    sourcedir = Path(__file__).parents[1] / \"templates\"\n    for source, target in USER_DATA_FILES.items():\n        targetdir = directory / target\n        if not targetdir.is_dir():\n            raise OperationalException(f\"Directory `{targetdir}` does not exist.\")\n        targetfile = targetdir / source\n        if targetfile.exists():\n            if not overwrite:\n                logger.warning(f\"File `{targetfile}` exists already, not deploying sample file.\")\n                continue\n            logger.warning(f\"File `{targetfile}` exists already, overwriting.\")\n        shutil.copy(str(sourcedir / source), str(targetfile))\n", "path": "freqtrade/configuration/directory_operations.py"}], "after_files": [{"content": "import logging\nimport secrets\nfrom pathlib import Path\nfrom typing import Any, Dict, List\n\nfrom questionary import Separator, prompt\n\nfrom freqtrade.configuration.directory_operations import chown_user_directory\nfrom freqtrade.constants import UNLIMITED_STAKE_AMOUNT\nfrom freqtrade.exceptions import OperationalException\nfrom freqtrade.exchange import MAP_EXCHANGE_CHILDCLASS, available_exchanges\nfrom freqtrade.misc import render_template\n\n\nlogger = logging.getLogger(__name__)\n\n\ndef validate_is_int(val):\n    try:\n        _ = int(val)\n        return True\n    except Exception:\n        return False\n\n\ndef validate_is_float(val):\n    try:\n        _ = float(val)\n        return True\n    except Exception:\n        return False\n\n\ndef ask_user_overwrite(config_path: Path) -> bool:\n    questions = [\n        {\n            \"type\": \"confirm\",\n            \"name\": \"overwrite\",\n            \"message\": f\"File {config_path} already exists. Overwrite?\",\n            \"default\": False,\n        },\n    ]\n    answers = prompt(questions)\n    return answers['overwrite']\n\n\ndef ask_user_config() -> Dict[str, Any]:\n    \"\"\"\n    Ask user a few questions to build the configuration.\n    Interactive questions built using https://github.com/tmbo/questionary\n    :returns: Dict with keys to put into template\n    \"\"\"\n    questions: List[Dict[str, Any]] = [\n        {\n            \"type\": \"confirm\",\n            \"name\": \"dry_run\",\n            \"message\": \"Do you want to enable Dry-run (simulated trades)?\",\n            \"default\": True,\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"stake_currency\",\n            \"message\": \"Please insert your stake currency:\",\n            \"default\": 'BTC',\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"stake_amount\",\n            \"message\": \"Please insert your stake amount:\",\n            \"default\": \"0.01\",\n            \"validate\": lambda val: val == UNLIMITED_STAKE_AMOUNT or validate_is_float(val),\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"max_open_trades\",\n            \"message\": f\"Please insert max_open_trades (Integer or '{UNLIMITED_STAKE_AMOUNT}'):\",\n            \"default\": \"3\",\n            \"validate\": lambda val: val == UNLIMITED_STAKE_AMOUNT or validate_is_int(val)\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"timeframe\",\n            \"message\": \"Please insert your desired timeframe (e.g. 5m):\",\n            \"default\": \"5m\",\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"fiat_display_currency\",\n            \"message\": \"Please insert your display Currency (for reporting):\",\n            \"default\": 'USD',\n        },\n        {\n            \"type\": \"select\",\n            \"name\": \"exchange_name\",\n            \"message\": \"Select exchange\",\n            \"choices\": [\n                \"binance\",\n                \"binanceus\",\n                \"bittrex\",\n                \"kraken\",\n                \"ftx\",\n                Separator(),\n                \"other\",\n            ],\n        },\n        {\n            \"type\": \"autocomplete\",\n            \"name\": \"exchange_name\",\n            \"message\": \"Type your exchange name (Must be supported by ccxt)\",\n            \"choices\": available_exchanges(),\n            \"when\": lambda x: x[\"exchange_name\"] == 'other'\n        },\n        {\n            \"type\": \"password\",\n            \"name\": \"exchange_key\",\n            \"message\": \"Insert Exchange Key\",\n            \"when\": lambda x: not x['dry_run']\n        },\n        {\n            \"type\": \"password\",\n            \"name\": \"exchange_secret\",\n            \"message\": \"Insert Exchange Secret\",\n            \"when\": lambda x: not x['dry_run']\n        },\n        {\n            \"type\": \"confirm\",\n            \"name\": \"telegram\",\n            \"message\": \"Do you want to enable Telegram?\",\n            \"default\": False,\n        },\n        {\n            \"type\": \"password\",\n            \"name\": \"telegram_token\",\n            \"message\": \"Insert Telegram token\",\n            \"when\": lambda x: x['telegram']\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"telegram_chat_id\",\n            \"message\": \"Insert Telegram chat id\",\n            \"when\": lambda x: x['telegram']\n        },\n        {\n            \"type\": \"confirm\",\n            \"name\": \"api_server\",\n            \"message\": \"Do you want to enable the Rest API (includes FreqUI)?\",\n            \"default\": False,\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"api_server_listen_addr\",\n            \"message\": \"Insert Api server Listen Address (best left untouched default!)\",\n            \"default\": \"127.0.0.1\",\n            \"when\": lambda x: x['api_server']\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"api_server_username\",\n            \"message\": \"Insert api-server username\",\n            \"default\": \"freqtrader\",\n            \"when\": lambda x: x['api_server']\n        },\n        {\n            \"type\": \"text\",\n            \"name\": \"api_server_password\",\n            \"message\": \"Insert api-server password\",\n            \"when\": lambda x: x['api_server']\n        },\n    ]\n    answers = prompt(questions)\n\n    if not answers:\n        # Interrupted questionary sessions return an empty dict.\n        raise OperationalException(\"User interrupted interactive questions.\")\n\n    # Force JWT token to be a random string\n    answers['api_server_jwt_key'] = secrets.token_hex()\n\n    return answers\n\n\ndef deploy_new_config(config_path: Path, selections: Dict[str, Any]) -> None:\n    \"\"\"\n    Applies selections to the template and writes the result to config_path\n    :param config_path: Path object for new config file. Should not exist yet\n    :param selecions: Dict containing selections taken by the user.\n    \"\"\"\n    from jinja2.exceptions import TemplateNotFound\n    try:\n        exchange_template = MAP_EXCHANGE_CHILDCLASS.get(\n            selections['exchange_name'], selections['exchange_name'])\n\n        selections['exchange'] = render_template(\n            templatefile=f\"subtemplates/exchange_{exchange_template}.j2\",\n            arguments=selections\n            )\n    except TemplateNotFound:\n        selections['exchange'] = render_template(\n            templatefile=\"subtemplates/exchange_generic.j2\",\n            arguments=selections\n        )\n\n    config_text = render_template(templatefile='base_config.json.j2',\n                                  arguments=selections)\n\n    logger.info(f\"Writing config to `{config_path}`.\")\n    logger.info(\n        \"Please make sure to check the configuration contents and adjust settings to your needs.\")\n\n    config_path.write_text(config_text)\n\n\ndef start_new_config(args: Dict[str, Any]) -> None:\n    \"\"\"\n    Create a new strategy from a template\n    Asking the user questions to fill out the templateaccordingly.\n    \"\"\"\n\n    config_path = Path(args['config'][0])\n    chown_user_directory(config_path.parent)\n    if config_path.exists():\n        overwrite = ask_user_overwrite(config_path)\n        if overwrite:\n            config_path.unlink()\n        else:\n            raise OperationalException(\n                f\"Configuration file `{config_path}` already exists. \"\n                \"Please delete it or use a different configuration file name.\")\n    selections = ask_user_config()\n    deploy_new_config(config_path, selections)\n", "path": "freqtrade/commands/build_config_commands.py"}, {"content": "import logging\nimport shutil\nfrom pathlib import Path\nfrom typing import Any, Dict, Optional\n\nfrom freqtrade.constants import USER_DATA_FILES\nfrom freqtrade.exceptions import OperationalException\n\n\nlogger = logging.getLogger(__name__)\n\n\ndef create_datadir(config: Dict[str, Any], datadir: Optional[str] = None) -> Path:\n\n    folder = Path(datadir) if datadir else Path(f\"{config['user_data_dir']}/data\")\n    if not datadir:\n        # set datadir\n        exchange_name = config.get('exchange', {}).get('name').lower()\n        folder = folder.joinpath(exchange_name)\n\n    if not folder.is_dir():\n        folder.mkdir(parents=True)\n        logger.info(f'Created data directory: {datadir}')\n    return folder\n\n\ndef chown_user_directory(directory: Path) -> None:\n    \"\"\"\n    Use Sudo to change permissions of the home-directory if necessary\n    Only applies when running in docker!\n    \"\"\"\n    import os\n    if os.environ.get('FT_APP_ENV') == 'docker':\n        try:\n            import subprocess\n            subprocess.check_output(\n                ['sudo', 'chown', '-R', 'ftuser:', str(directory.resolve())])\n        except Exception:\n            logger.warning(f\"Could not chown {directory}\")\n\n\ndef create_userdata_dir(directory: str, create_dir: bool = False) -> Path:\n    \"\"\"\n    Create userdata directory structure.\n    if create_dir is True, then the parent-directory will be created if it does not exist.\n    Sub-directories will always be created if the parent directory exists.\n    Raises OperationalException if given a non-existing directory.\n    :param directory: Directory to check\n    :param create_dir: Create directory if it does not exist.\n    :return: Path object containing the directory\n    \"\"\"\n    sub_dirs = [\"backtest_results\", \"data\", \"hyperopts\", \"hyperopt_results\", \"logs\",\n                \"notebooks\", \"plot\", \"strategies\", ]\n    folder = Path(directory)\n    chown_user_directory(folder)\n    if not folder.is_dir():\n        if create_dir:\n            folder.mkdir(parents=True)\n            logger.info(f'Created user-data directory: {folder}')\n        else:\n            raise OperationalException(\n                f\"Directory `{folder}` does not exist. \"\n                \"Please use `freqtrade create-userdir` to create a user directory\")\n\n    # Create required subdirectories\n    for f in sub_dirs:\n        subfolder = folder / f\n        if not subfolder.is_dir():\n            subfolder.mkdir(parents=False)\n    return folder\n\n\ndef copy_sample_files(directory: Path, overwrite: bool = False) -> None:\n    \"\"\"\n    Copy files from templates to User data directory.\n    :param directory: Directory to copy data to\n    :param overwrite: Overwrite existing sample files\n    \"\"\"\n    if not directory.is_dir():\n        raise OperationalException(f\"Directory `{directory}` does not exist.\")\n    sourcedir = Path(__file__).parents[1] / \"templates\"\n    for source, target in USER_DATA_FILES.items():\n        targetdir = directory / target\n        if not targetdir.is_dir():\n            raise OperationalException(f\"Directory `{targetdir}` does not exist.\")\n        targetfile = targetdir / source\n        if targetfile.exists():\n            if not overwrite:\n                logger.warning(f\"File `{targetfile}` exists already, not deploying sample file.\")\n                continue\n            logger.warning(f\"File `{targetfile}` exists already, overwriting.\")\n        shutil.copy(str(sourcedir / source), str(targetfile))\n", "path": "freqtrade/configuration/directory_operations.py"}]}