From 9652c00acbf4f5c1949806390db29a6ba04ed6b9 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 25 Jan 2023 12:20:10 +0100 Subject: [PATCH 1/6] Don't amend docker manifest --- build_helpers/publish_docker_arm64.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build_helpers/publish_docker_arm64.sh b/build_helpers/publish_docker_arm64.sh index 071eb0fa2..4cbdf0cb4 100755 --- a/build_helpers/publish_docker_arm64.sh +++ b/build_helpers/publish_docker_arm64.sh @@ -70,7 +70,7 @@ docker push ${CACHE_IMAGE}:$TAG_ARM # Otherwise installation might fail. echo "create manifests" -docker manifest create --amend ${IMAGE_NAME}:${TAG} ${CACHE_IMAGE}:${TAG_ARM} ${IMAGE_NAME}:${TAG_PI} ${CACHE_IMAGE}:${TAG} +docker manifest create ${IMAGE_NAME}:${TAG} ${CACHE_IMAGE}:${TAG_ARM} ${IMAGE_NAME}:${TAG_PI} ${CACHE_IMAGE}:${TAG} docker manifest push -p ${IMAGE_NAME}:${TAG} docker manifest create ${IMAGE_NAME}:${TAG_PLOT} ${CACHE_IMAGE}:${TAG_PLOT_ARM} ${CACHE_IMAGE}:${TAG_PLOT} @@ -84,6 +84,7 @@ docker manifest push -p ${IMAGE_NAME}:${TAG_FREQAI_RL} # Tag as latest for develop builds if [ "${TAG}" = "develop" ]; then + echo 'Tagging image as latest' docker manifest create ${IMAGE_NAME}:latest ${CACHE_IMAGE}:${TAG_ARM} ${IMAGE_NAME}:${TAG_PI} ${CACHE_IMAGE}:${TAG} docker manifest push -p ${IMAGE_NAME}:latest fi From bd913bc24d08bb92a993b65e642513e27bd4a602 Mon Sep 17 00:00:00 2001 From: Matthias Date: Wed, 25 Jan 2023 14:34:52 +0100 Subject: [PATCH 2/6] Disable provenance in buildx config for pi image --- build_helpers/publish_docker_arm64.sh | 8 ++++---- build_helpers/publish_docker_multi.sh | 15 ++++++++++----- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/build_helpers/publish_docker_arm64.sh b/build_helpers/publish_docker_arm64.sh index 4cbdf0cb4..f3cedff2e 100755 --- a/build_helpers/publish_docker_arm64.sh +++ b/build_helpers/publish_docker_arm64.sh @@ -70,16 +70,16 @@ docker push ${CACHE_IMAGE}:$TAG_ARM # Otherwise installation might fail. echo "create manifests" -docker manifest create ${IMAGE_NAME}:${TAG} ${CACHE_IMAGE}:${TAG_ARM} ${IMAGE_NAME}:${TAG_PI} ${CACHE_IMAGE}:${TAG} +docker manifest create ${IMAGE_NAME}:${TAG} ${CACHE_IMAGE}:${TAG} ${CACHE_IMAGE}:${TAG_ARM} ${IMAGE_NAME}:${TAG_PI} docker manifest push -p ${IMAGE_NAME}:${TAG} -docker manifest create ${IMAGE_NAME}:${TAG_PLOT} ${CACHE_IMAGE}:${TAG_PLOT_ARM} ${CACHE_IMAGE}:${TAG_PLOT} +docker manifest create ${IMAGE_NAME}:${TAG_PLOT} ${CACHE_IMAGE}:${TAG_PLOT} ${CACHE_IMAGE}:${TAG_PLOT_ARM} docker manifest push -p ${IMAGE_NAME}:${TAG_PLOT} -docker manifest create ${IMAGE_NAME}:${TAG_FREQAI} ${CACHE_IMAGE}:${TAG_FREQAI_ARM} ${CACHE_IMAGE}:${TAG_FREQAI} +docker manifest create ${IMAGE_NAME}:${TAG_FREQAI} ${CACHE_IMAGE}:${TAG_FREQAI} ${CACHE_IMAGE}:${TAG_FREQAI_ARM} docker manifest push -p ${IMAGE_NAME}:${TAG_FREQAI} -docker manifest create ${IMAGE_NAME}:${TAG_FREQAI_RL} ${CACHE_IMAGE}:${TAG_FREQAI_RL_ARM} ${CACHE_IMAGE}:${TAG_FREQAI_RL} +docker manifest create ${IMAGE_NAME}:${TAG_FREQAI_RL} ${CACHE_IMAGE}:${TAG_FREQAI_RL} ${CACHE_IMAGE}:${TAG_FREQAI_RL_ARM} docker manifest push -p ${IMAGE_NAME}:${TAG_FREQAI_RL} # Tag as latest for develop builds diff --git a/build_helpers/publish_docker_multi.sh b/build_helpers/publish_docker_multi.sh index a608c1282..3e5e61564 100755 --- a/build_helpers/publish_docker_multi.sh +++ b/build_helpers/publish_docker_multi.sh @@ -26,7 +26,10 @@ if [ "${GITHUB_EVENT_NAME}" = "schedule" ]; then --cache-to=type=registry,ref=${CACHE_TAG} \ -f docker/Dockerfile.armhf \ --platform ${PI_PLATFORM} \ - -t ${IMAGE_NAME}:${TAG_PI} --push . + -t ${IMAGE_NAME}:${TAG_PI} \ + --push \ + --provenance=false \ + . else echo "event ${GITHUB_EVENT_NAME}: building with cache" # Build regular image @@ -35,12 +38,16 @@ else # Pull last build to avoid rebuilding the whole image # docker pull --platform ${PI_PLATFORM} ${IMAGE_NAME}:${TAG} + # disable provenance due to https://github.com/docker/buildx/issues/1509 docker buildx build \ --cache-from=type=registry,ref=${CACHE_TAG} \ --cache-to=type=registry,ref=${CACHE_TAG} \ -f docker/Dockerfile.armhf \ --platform ${PI_PLATFORM} \ - -t ${IMAGE_NAME}:${TAG_PI} --push . + -t ${IMAGE_NAME}:${TAG_PI} \ + --push \ + --provenance=false \ + . fi if [ $? -ne 0 ]; then @@ -68,12 +75,10 @@ fi docker images -docker push ${CACHE_IMAGE} +docker push ${CACHE_IMAGE}:$TAG docker push ${CACHE_IMAGE}:$TAG_PLOT docker push ${CACHE_IMAGE}:$TAG_FREQAI docker push ${CACHE_IMAGE}:$TAG_FREQAI_RL -docker push ${CACHE_IMAGE}:$TAG - docker images From 2333dbae40fbbb916bb5aef4b270a7eb0c3286ca Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 26 Jan 2023 07:04:02 +0100 Subject: [PATCH 3/6] Update reinforcement learning docs to use correct naming --- docs/freqai-reinforcement-learning.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/freqai-reinforcement-learning.md b/docs/freqai-reinforcement-learning.md index 4442a2f4f..f78a392a3 100644 --- a/docs/freqai-reinforcement-learning.md +++ b/docs/freqai-reinforcement-learning.md @@ -52,18 +52,18 @@ where `ReinforcementLearner` will use the templated `ReinforcementLearner` from """ # For RL, there are no direct targets to set. This is filler (neutral) # until the agent sends an action. - df["&-action"] = 0 + dataframe["&-action"] = 0 ``` Most of the function remains the same as for typical Regressors, however, the function above shows how the strategy must pass the raw price data to the agent so that it has access to raw OHLCV in the training environment: ```python - def feature_engineering_standard(): + def feature_engineering_standard(self, dataframe, **kwargs): # The following features are necessary for RL models - informative[f"%-raw_close"] = informative["close"] - informative[f"%-raw_open"] = informative["open"] - informative[f"%-raw_high"] = informative["high"] - informative[f"%-raw_low"] = informative["low"] + dataframe[f"%-raw_close"] = dataframe["close"] + dataframe[f"%-raw_open"] = dataframe["open"] + dataframe[f"%-raw_high"] = dataframe["high"] + dataframe[f"%-raw_low"] = dataframe["low"] ``` Finally, there is no explicit "label" to make - instead it is necessary to assign the `&-action` column which will contain the agent's actions when accessed in `populate_entry/exit_trends()`. In the present example, the neutral action to 0. This value should align with the environment used. FreqAI provides two environments, both use 0 as the neutral action. From 8647c0192ca3534bf576923cb55edd77430ed429 Mon Sep 17 00:00:00 2001 From: Matthias Date: Thu, 26 Jan 2023 07:08:38 +0100 Subject: [PATCH 4/6] Fix typo --- docs/freqai-reinforcement-learning.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/freqai-reinforcement-learning.md b/docs/freqai-reinforcement-learning.md index f78a392a3..5c9733403 100644 --- a/docs/freqai-reinforcement-learning.md +++ b/docs/freqai-reinforcement-learning.md @@ -34,7 +34,7 @@ Setting up and running a Reinforcement Learning model is the same as running a R freqtrade trade --freqaimodel ReinforcementLearner --strategy MyRLStrategy --config config.json ``` -where `ReinforcementLearner` will use the templated `ReinforcementLearner` from `freqai/prediction_models/ReinforcementLearner` (or a custom user defined one located in `user_data/freqaimodels`). The strategy, on the other hand, follows the same base [feature engineering](freqai-feature-engineering.md) with `feature_engineering_*` as a typical Regressor. The difference lies in the creation of the targets, Reinforcement Learning doesnt require them. However, FreqAI requires a default (neutral) value to be set in the action column: +where `ReinforcementLearner` will use the templated `ReinforcementLearner` from `freqai/prediction_models/ReinforcementLearner` (or a custom user defined one located in `user_data/freqaimodels`). The strategy, on the other hand, follows the same base [feature engineering](freqai-feature-engineering.md) with `feature_engineering_*` as a typical Regressor. The difference lies in the creation of the targets, Reinforcement Learning doesn't require them. However, FreqAI requires a default (neutral) value to be set in the action column: ```python def set_freqai_targets(self, dataframe, **kwargs): @@ -243,7 +243,6 @@ FreqAI also provides a built in episodic summary logger called `self.tensorboard !!! Note The `self.tensorboard_log()` function is designed for tracking incremented objects only i.e. events, actions inside the training environment. If the event of interest is a float, the float can be passed as the second argument e.g. `self.tensorboard_log("float_metric1", 0.23)` would add 0.23 to `float_metric`. In this case you can also disable incrementing using `inc=False` parameter. - ### Choosing a base environment FreqAI provides three base environments, `Base3ActionRLEnvironment`, `Base4ActionEnvironment` and `Base5ActionEnvironment`. As the names imply, the environments are customized for agents that can select from 3, 4 or 5 actions. The `Base3ActionEnvironment` is the simplest, the agent can select from hold, long, or short. This environment can also be used for long-only bots (it automatically follows the `can_short` flag from the strategy), where long is the enter condition and short is the exit condition. Meanwhile, in the `Base4ActionEnvironment`, the agent can enter long, enter short, hold neutral, or exit position. Finally, in the `Base5ActionEnvironment`, the agent has the same actions as Base4, but instead of a single exit action, it separates exit long and exit short. The main changes stemming from the environment selection include: From aa15837589c8e48ee42a73438bf6314c2ce8749a Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 27 Jan 2023 20:14:12 +0100 Subject: [PATCH 5/6] Add test for filled_date not updating if it's already set --- tests/persistence/test_persistence.py | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/persistence/test_persistence.py b/tests/persistence/test_persistence.py index e12e919fc..d06f05179 100644 --- a/tests/persistence/test_persistence.py +++ b/tests/persistence/test_persistence.py @@ -1868,7 +1868,10 @@ def test_get_exit_order_count(fee, is_short): @pytest.mark.usefixtures("init_persistence") -def test_update_order_from_ccxt(caplog): +def test_update_order_from_ccxt(caplog, time_machine): + start = datetime(2023, 1, 1, 4, tzinfo=timezone.utc) + time_machine.move_to(start, tick=False) + # Most basic order return (only has orderid) o = Order.parse_from_ccxt_object({'id': '1234'}, 'ADA/USDT', 'buy', 20.01, 1234.6) assert isinstance(o, Order) @@ -1917,7 +1920,9 @@ def test_update_order_from_ccxt(caplog): assert o.filled == 20.0 assert o.remaining == 0.0 assert not o.ft_is_open - assert o.order_filled_date is not None + assert o.order_filled_date == start + # Move time + time_machine.move_to(start + timedelta(hours=1), tick=False) ccxt_order.update({'id': 'somethingelse'}) with pytest.raises(DependencyException, match=r"Order-id's don't match"): @@ -1930,6 +1935,12 @@ def test_update_order_from_ccxt(caplog): # Call regular update - shouldn't fail. Order.update_orders([o], {'id': '1234'}) + assert o.order_filled_date == start + + # Fill order again - shouldn't update filled date + ccxt_order.update({'id': '1234'}) + Order.update_orders([o], ccxt_order) + assert o.order_filled_date == start @pytest.mark.usefixtures("init_persistence") From 020dc3c6e13baaedd43715126ec689d878b35a53 Mon Sep 17 00:00:00 2001 From: Matthias Date: Fri, 27 Jan 2023 20:21:29 +0100 Subject: [PATCH 6/6] filled-date shouldn't update again --- freqtrade/persistence/trade_model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/freqtrade/persistence/trade_model.py b/freqtrade/persistence/trade_model.py index 75da3ddfd..daeccb216 100644 --- a/freqtrade/persistence/trade_model.py +++ b/freqtrade/persistence/trade_model.py @@ -146,7 +146,7 @@ class Order(_DECL_BASE): # Assign funding fee up to this point # (represents the funding fee since the last order) self.funding_fee = self.trade.funding_fees - if (order.get('filled', 0.0) or 0.0) > 0: + if (order.get('filled', 0.0) or 0.0) > 0 and not self.order_filled_date: self.order_filled_date = datetime.now(timezone.utc) self.order_update_date = datetime.now(timezone.utc)