Repository: freqtrade/freqtrade

Issue:
Unable to built docker pi image on raspberry pi 3
Hi, 

I don't succeed building the image on a rasberry pi 3.

OS "Raspbian GNU/Linux 9 (stretch)"

```
> pi@GP-RB-FRONT:~/freqtrade/freqtrade $ docker build . -f Dockerfile.pi -t freqtrade
> Sending build context to Docker daemon  19.51MB
> Step 1/15 : FROM balenalib/raspberrypi3-debian:stretch
>  ---> 72b8e4ae9043
> Step 2/15 : RUN [ "cross-build-start" ]
>  ---> Running in 66dfc8472a92
> standard_init_linux.go:211: exec user process caused "exec format error"
> The command 'cross-build-start' returned a non-zero code: 1
```

Have a nice day.



Discussion:
My advice is to upgrade pi3 to buster then use normal linux installs.
I am using that way.
hi @gaugau3000 ,

the way this image works is to cross-build it on a normal pc and then export/import it to the raspberry as building this on the raspberry would take ages.

I've been trying to set this up in CI but travis times out ... 

Hope this helps
I got it :-) will try. Many tks !
I will actually still try to publish this somehow (either through Github actions, or through azure ...) - but i lacked the time to set this up completely)
I don't succeed building the image on windows.

Complete output from command /root/berryconda3/bin/python -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-0jh40zzd/scikit-learn/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-b2x3hq_s-record/install-record.txt --single-version-externally-managed --compile:
    Partial import of sklearn during the build process.
    Traceback (most recent call last):
      File "<string>", line 1, in <module>
      File "/tmp/pip-build-0jh40zzd/scikit-learn/setup.py", line 290, in <module>
        setup_package()
      File "/tmp/pip-build-0jh40zzd/scikit-learn/setup.py", line 286, in setup_package
        setup(**metadata)
      File "/root/berryconda3/lib/python3.6/site-packages/numpy/distutils/core.py", line 135, in setup
        config = configuration()
      File "/tmp/pip-build-0jh40zzd/scikit-learn/setup.py", line 174, in configuration
        config.add_subpackage('sklearn')
      File "/root/berryconda3/lib/python3.6/site-packages/numpy/distutils/misc_util.py", line 1034, in add_subpackage
        caller_level = 2)
      File "/root/berryconda3/lib/python3.6/site-packages/numpy/distutils/misc_util.py", line 1003, in get_subpackage
        caller_level = caller_level + 1)
      File "/root/berryconda3/lib/python3.6/site-packages/numpy/distutils/misc_util.py", line 940, in _get_configuration_from_setup_py
        config = setup_module.configuration(*args)
      File "sklearn/setup.py", line 62, in configuration
        config.add_subpackage('utils')
      File "/root/berryconda3/lib/python3.6/site-packages/numpy/distutils/misc_util.py", line 1034, in add_subpackage
        caller_level = 2)
      File "/root/berryconda3/lib/python3.6/site-packages/numpy/distutils/misc_util.py", line 1003, in get_subpackage
        caller_level = caller_level + 1)
      File "/root/berryconda3/lib/python3.6/site-packages/numpy/distutils/misc_util.py", line 940, in _get_configuration_from_setup_py
        config = setup_module.configuration(*args)
      File "sklearn/utils/setup.py", line 8, in configuration
        from Cython import Tempita
    ModuleNotFoundError: No module named 'Cython'

    ----------------------------------------
Command "/root/berryconda3/bin/python -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-0jh40zzd/scikit-learn/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-b2x3hq_s-record/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-build-0jh40zzd/scikit-learn/
You are using pip version 9.0.1, however version 19.2.3 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
The command '/bin/sh -c ~/berryconda3/bin/conda install -y numpy pandas scipy  && ~/berryconda3/bin/pip install -r requirements-common.txt --no-cache-dir' returned a non-zero code: 1

Many tks.

a quick fix is adding `cython` to  the `conda install` line, so itlooks as follows:
```patch
 # Install dependencies
 COPY requirements-common.txt /freqtrade/
-RUN ~/berryconda3/bin/conda install -y numpy pandas scipy \
+RUN ~/berryconda3/bin/conda install -y cython numpy pandas scipy \
  && ~/berryconda3/bin/pip install -r requirements-common.txt --no-cache-dir
 
```

For now, i'll not create a PR for this as i think there is a simpler solution which will speed up generating this image - but that will require some more testing.

Resolving patch:
diff --git a/freqtrade/optimize/__init__.py b/freqtrade/optimize/__init__.py
--- a/freqtrade/optimize/__init__.py
+++ b/freqtrade/optimize/__init__.py
@@ -1,9 +1,7 @@
 import logging
 from typing import Any, Dict
 
-from filelock import FileLock, Timeout
-
-from freqtrade import DependencyException, constants
+from freqtrade import DependencyException, constants, OperationalException
 from freqtrade.state import RunMode
 from freqtrade.utils import setup_utils_configuration
 
@@ -53,8 +51,12 @@ def start_hyperopt(args: Dict[str, Any]) -> None:
     :return: None
     """
     # Import here to avoid loading hyperopt module when it's not used
-    from freqtrade.optimize.hyperopt import Hyperopt
-
+    try:
+        from filelock import FileLock, Timeout
+        from freqtrade.optimize.hyperopt import Hyperopt
+    except ImportError as e:
+        raise OperationalException(
+            f"{e}. Please ensure that the hyperopt dependencies are installed.") from e
     # Initialize configuration
     config = setup_configuration(args, RunMode.HYPEROPT)
 
diff --git a/setup.py b/setup.py
--- a/setup.py
+++ b/setup.py
@@ -18,6 +18,13 @@
 # Requirements used for submodules
 api = ['flask']
 plot = ['plotly>=4.0']
+hyperopt = [
+    'scipy',
+    'scikit-learn',
+    'scikit-optimize',
+    'filelock',
+    'joblib',
+    ]
 
 develop = [
     'coveralls',
@@ -38,7 +45,7 @@
     'ipykernel',
     ]
 
-all_extra = api + plot + develop + jupyter
+all_extra = api + plot + develop + jupyter + hyperopt
 
 setup(name='freqtrade',
       version=__version__,
@@ -62,14 +69,10 @@
           'requests',
           'urllib3',
           'wrapt',
-          'scikit-learn',
-          'joblib',
           'jsonschema',
           'TA-Lib',
           'tabulate',
           'coinmarketcap',
-          'scikit-optimize',
-          'filelock',
           'py_find_1st',
           'python-rapidjson',
           'sdnotify',
@@ -77,15 +80,14 @@
           # from requirements.txt
           'numpy',
           'pandas',
-          'scipy',
       ],
       extras_require={
           'api': api,
           'dev': all_extra,
           'plot': plot,
-          'all': all_extra,
           'jupyter': jupyter,
-
+          'hyperopt': hyperopt,
+          'all': all_extra,
       },
       include_package_data=True,
       zip_safe=False,


Test patch:
diff --git a/tests/conftest.py b/tests/conftest.py
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -1054,3 +1054,24 @@ def rpc_balance():
 def testdatadir() -> Path:
     """Return the path where testdata files are stored"""
     return (Path(__file__).parent / "testdata").resolve()
+
+
+@pytest.fixture(scope="function")
+def import_fails() -> None:
+    # Source of this test-method:
+    # https://stackoverflow.com/questions/2481511/mocking-importerror-in-python
+    import builtins
+    realimport = builtins.__import__
+
+    def mockedimport(name, *args, **kwargs):
+        if name in ["filelock"]:
+            raise ImportError(f"No module named '{name}'")
+        return realimport(name, *args, **kwargs)
+
+    builtins.__import__ = mockedimport
+
+    # Run test - then cleanup
+    yield
+
+    # restore previous importfunction
+    builtins.__import__ = realimport
diff --git a/tests/optimize/test_hyperopt.py b/tests/optimize/test_hyperopt.py
--- a/tests/optimize/test_hyperopt.py
+++ b/tests/optimize/test_hyperopt.py
@@ -190,6 +190,24 @@ def test_hyperoptlossresolver_wrongname(mocker, default_conf, caplog) -> None:
         HyperOptLossResolver(default_conf, ).hyperopt
 
 
+def test_start_not_installed(mocker, default_conf, caplog, import_fails) -> None:
+    start_mock = MagicMock()
+    patched_configuration_load_config_file(mocker, default_conf)
+
+    mocker.patch('freqtrade.optimize.hyperopt.Hyperopt.start', start_mock)
+    patch_exchange(mocker)
+
+    args = [
+        '--config', 'config.json',
+        'hyperopt',
+        '--epochs', '5'
+    ]
+    args = get_args(args)
+
+    with pytest.raises(OperationalException, match=r"Please ensure that the hyperopt dependencies"):
+        start_hyperopt(args)
+
+
 def test_start(mocker, default_conf, caplog) -> None:
     start_mock = MagicMock()
     patched_configuration_load_config_file(mocker, default_conf)