2019-07-12 00:26:27 +00:00
|
|
|
import logging
|
2019-11-01 12:28:35 +00:00
|
|
|
import shutil
|
2019-07-17 18:53:29 +00:00
|
|
|
from pathlib import Path
|
2022-09-18 11:20:36 +00:00
|
|
|
from typing import Optional
|
2019-07-12 00:26:27 +00:00
|
|
|
|
2023-07-23 17:38:30 +00:00
|
|
|
from freqtrade.configuration.detect_environment import running_in_docker
|
2024-05-12 13:18:32 +00:00
|
|
|
from freqtrade.constants import (
|
|
|
|
USER_DATA_FILES,
|
|
|
|
USERPATH_FREQAIMODELS,
|
|
|
|
USERPATH_HYPEROPTS,
|
|
|
|
USERPATH_NOTEBOOKS,
|
|
|
|
USERPATH_STRATEGIES,
|
|
|
|
Config,
|
|
|
|
)
|
2020-09-28 17:39:41 +00:00
|
|
|
from freqtrade.exceptions import OperationalException
|
|
|
|
|
2019-07-12 00:26:27 +00:00
|
|
|
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2022-09-18 11:20:36 +00:00
|
|
|
def create_datadir(config: Config, datadir: Optional[str] = None) -> Path:
|
2019-07-21 12:32:29 +00:00
|
|
|
folder = Path(datadir) if datadir else Path(f"{config['user_data_dir']}/data")
|
2019-07-12 00:26:27 +00:00
|
|
|
if not datadir:
|
|
|
|
# set datadir
|
2024-05-12 14:29:24 +00:00
|
|
|
exchange_name = config.get("exchange", {}).get("name", "").lower()
|
2019-07-17 18:53:29 +00:00
|
|
|
folder = folder.joinpath(exchange_name)
|
2019-07-12 00:26:27 +00:00
|
|
|
|
2019-07-17 18:53:29 +00:00
|
|
|
if not folder.is_dir():
|
|
|
|
folder.mkdir(parents=True)
|
2024-05-12 14:29:24 +00:00
|
|
|
logger.info(f"Created data directory: {datadir}")
|
2019-12-23 14:09:17 +00:00
|
|
|
return folder
|
2019-07-21 11:42:56 +00:00
|
|
|
|
|
|
|
|
2021-04-08 18:07:52 +00:00
|
|
|
def chown_user_directory(directory: Path) -> None:
|
|
|
|
"""
|
|
|
|
Use Sudo to change permissions of the home-directory if necessary
|
|
|
|
Only applies when running in docker!
|
|
|
|
"""
|
2023-07-23 17:38:30 +00:00
|
|
|
if running_in_docker():
|
2021-04-08 18:07:52 +00:00
|
|
|
try:
|
2024-07-05 06:25:24 +00:00
|
|
|
import subprocess # noqa: S404
|
2024-05-12 14:29:24 +00:00
|
|
|
|
|
|
|
subprocess.check_output(["sudo", "chown", "-R", "ftuser:", str(directory.resolve())])
|
2021-04-08 18:07:52 +00:00
|
|
|
except Exception:
|
|
|
|
logger.warning(f"Could not chown {directory}")
|
|
|
|
|
|
|
|
|
2020-02-02 04:00:40 +00:00
|
|
|
def create_userdata_dir(directory: str, create_dir: bool = False) -> Path:
|
2019-07-31 17:39:54 +00:00
|
|
|
"""
|
|
|
|
Create userdata directory structure.
|
|
|
|
if create_dir is True, then the parent-directory will be created if it does not exist.
|
|
|
|
Sub-directories will always be created if the parent directory exists.
|
|
|
|
Raises OperationalException if given a non-existing directory.
|
|
|
|
:param directory: Directory to check
|
|
|
|
:param create_dir: Create directory if it does not exist.
|
|
|
|
:return: Path object containing the directory
|
|
|
|
"""
|
2024-05-12 14:29:24 +00:00
|
|
|
sub_dirs = [
|
|
|
|
"backtest_results",
|
|
|
|
"data",
|
|
|
|
USERPATH_HYPEROPTS,
|
|
|
|
"hyperopt_results",
|
|
|
|
"logs",
|
|
|
|
USERPATH_NOTEBOOKS,
|
|
|
|
"plot",
|
|
|
|
USERPATH_STRATEGIES,
|
|
|
|
USERPATH_FREQAIMODELS,
|
|
|
|
]
|
2019-07-21 11:42:56 +00:00
|
|
|
folder = Path(directory)
|
2021-04-08 18:07:52 +00:00
|
|
|
chown_user_directory(folder)
|
2019-07-21 11:42:56 +00:00
|
|
|
if not folder.is_dir():
|
2019-07-31 17:39:54 +00:00
|
|
|
if create_dir:
|
|
|
|
folder.mkdir(parents=True)
|
2024-05-12 14:29:24 +00:00
|
|
|
logger.info(f"Created user-data directory: {folder}")
|
2019-07-31 17:39:54 +00:00
|
|
|
else:
|
|
|
|
raise OperationalException(
|
|
|
|
f"Directory `{folder}` does not exist. "
|
2024-05-12 14:29:24 +00:00
|
|
|
"Please use `freqtrade create-userdir` to create a user directory"
|
|
|
|
)
|
2019-07-21 11:42:56 +00:00
|
|
|
|
|
|
|
# Create required subdirectories
|
|
|
|
for f in sub_dirs:
|
|
|
|
subfolder = folder / f
|
|
|
|
if not subfolder.is_dir():
|
2024-09-28 08:17:52 +00:00
|
|
|
if subfolder.exists() or subfolder.is_symlink():
|
2024-09-28 07:54:49 +00:00
|
|
|
raise OperationalException(
|
|
|
|
f"File `{subfolder}` exists already and is not a directory. "
|
|
|
|
"Freqtrade requires this to be a directory."
|
|
|
|
)
|
2019-07-21 11:42:56 +00:00
|
|
|
subfolder.mkdir(parents=False)
|
2019-07-21 13:49:52 +00:00
|
|
|
return folder
|
2019-11-01 12:28:35 +00:00
|
|
|
|
|
|
|
|
2019-11-01 13:08:55 +00:00
|
|
|
def copy_sample_files(directory: Path, overwrite: bool = False) -> None:
|
2019-11-01 12:28:35 +00:00
|
|
|
"""
|
|
|
|
Copy files from templates to User data directory.
|
|
|
|
:param directory: Directory to copy data to
|
2019-11-01 13:08:55 +00:00
|
|
|
:param overwrite: Overwrite existing sample files
|
2019-11-01 12:28:35 +00:00
|
|
|
"""
|
|
|
|
if not directory.is_dir():
|
|
|
|
raise OperationalException(f"Directory `{directory}` does not exist.")
|
|
|
|
sourcedir = Path(__file__).parents[1] / "templates"
|
|
|
|
for source, target in USER_DATA_FILES.items():
|
|
|
|
targetdir = directory / target
|
|
|
|
if not targetdir.is_dir():
|
|
|
|
raise OperationalException(f"Directory `{targetdir}` does not exist.")
|
|
|
|
targetfile = targetdir / source
|
|
|
|
if targetfile.exists():
|
2019-11-01 13:08:55 +00:00
|
|
|
if not overwrite:
|
|
|
|
logger.warning(f"File `{targetfile}` exists already, not deploying sample file.")
|
|
|
|
continue
|
2021-03-21 11:44:34 +00:00
|
|
|
logger.warning(f"File `{targetfile}` exists already, overwriting.")
|
2019-11-01 12:28:35 +00:00
|
|
|
shutil.copy(str(sourcedir / source), str(targetfile))
|