]> Piment Noir Git Repositories - freqai-strategies.git/commitdiff
fix(reforcexy): ensure padding frame is init with zeros
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Sat, 27 Sep 2025 15:29:28 +0000 (17:29 +0200)
committerJérôme Benoit <jerome.benoit@piment-noir.org>
Sat, 27 Sep 2025 15:29:28 +0000 (17:29 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@piment-noir.org>
ReforceXY/user_data/freqaimodels/ReforceXY.py
quickadapter/user_data/strategies/QuickAdapterV3.py
scripts/docker-upgrade.sh

index b35a8ab6dd77b3ff9e8d23b8f390b998d2e044d5..3fc9bf8e7ecc9182913f9b6ab64a22c1d6d0816a 100644 (file)
@@ -160,7 +160,7 @@ class ReforceXY(BaseReinforcementLearningModel):
         self.unset_unsupported()
 
     @staticmethod
-    def is_short_allowed(trading_mode: str) -> bool:
+    def _is_short_allowed(trading_mode: str) -> bool:
         if trading_mode in {"margin", "futures"}:
             return True
         elif trading_mode == "spot":
@@ -188,7 +188,7 @@ class ReforceXY(BaseReinforcementLearningModel):
         position: Positions,
         force_action: Optional[ForceActions] = None,
     ) -> NDArray[np.bool_]:
-        is_short_allowed = ReforceXY.is_short_allowed(trading_mode)
+        is_short_allowed = ReforceXY._is_short_allowed(trading_mode)
         position = ReforceXY._normalize_position(position)
 
         action_masks = np.zeros(len(Actions), dtype=np.bool_)
@@ -684,14 +684,18 @@ class ReforceXY(BaseReinforcementLearningModel):
                     del fb[0 : len(fb) - frame_stacking]
                 if len(fb) < frame_stacking:
                     pad_count = frame_stacking - len(fb)
-                    pad_frame = fb[0] if fb else np_observation
+                    pad_frame = np.zeros_like(np_observation, dtype=np.float32)
                     fb_padded = [pad_frame] * pad_count + fb
                 else:
                     fb_padded = fb
                 stacked_observations = np.concatenate(fb_padded, axis=1)
-                observations = stacked_observations.reshape(1, -1)
+                observations = stacked_observations.reshape(
+                    1, stacked_observations.shape[0], stacked_observations.shape[1]
+                )
             else:
-                observations = np_observation.reshape(1, -1)
+                observations = np_observation.reshape(
+                    1, np_observation.shape[0], np_observation.shape[1]
+                )
 
             if self.action_masking and self.inference_masking:
                 action_masks_param["action_masks"] = ReforceXY.get_action_masks(
index e48c2a3c236524ce0991f79af185b60e6ad2402f..6c43055c7a37d229b4150cc13e72d4293ae63c26 100644 (file)
@@ -224,18 +224,15 @@ class QuickAdapterV3(IStrategy):
                     ),
                 }
             )
+        self._candle_duration_secs = int(
+            timeframe_to_minutes(self.config.get("timeframe")) * 60
+        )
+        self.last_candle_start_secs: dict[str, Optional[int]] = {
+            pair: None for pair in self.pairs
+        }
         process_throttle_secs = self.config.get("internals", {}).get(
             "process_throttle_secs", 5
         )
-        self._throttle_modulo = max(
-            1,
-            int(
-                round(
-                    (timeframe_to_minutes(self.config.get("timeframe")) * 60)
-                    / process_throttle_secs
-                )
-            ),
-        )
         self._max_history_size = int(12 * 60 * 60 / process_throttle_secs)
         self._pnl_momentum_window_size = int(30 * 60 / process_throttle_secs)
         self._exit_thresholds_calibration: dict[str, float] = {
@@ -791,7 +788,10 @@ class QuickAdapterV3(IStrategy):
         current_time: datetime.datetime,
         callback: Callable[[], None],
     ) -> None:
-        if hash(pair + str(current_time)) % self._throttle_modulo == 0:
+        timestamp = int(current_time.timestamp())
+        candle_start_secs = timestamp - (timestamp % self._candle_duration_secs)
+        if candle_start_secs != self.last_candle_start_secs.get(pair):
+            self.last_candle_start_secs[pair] = candle_start_secs
             try:
                 callback()
             except Exception as e:
@@ -1119,7 +1119,7 @@ class QuickAdapterV3(IStrategy):
         side: str,
         order: Literal["entry", "exit"],
         rate: float,
-        min_natr_ratio_percent: float = 0.005,
+        min_natr_ratio_percent: float = 0.0075,
         max_natr_ratio_percent: float = 0.025,
         lookback_period: int = 1,
         decay_ratio: float = 0.5,
@@ -1551,6 +1551,11 @@ class QuickAdapterV3(IStrategy):
         side: str,
         **kwargs,
     ) -> bool:
+        if side not in {"long", "short"}:
+            return False
+        if side == "short" and not self.can_short:
+            logger.info(f"User denied short entry for {pair}: shorting not allowed")
+            return False
         if Trade.get_open_trade_count() >= self.config.get("max_open_trades"):
             return False
         max_open_trades_per_side = self.max_open_trades_per_side
index d82b1472976fc59b4afa977d9ba4ec8e1f94d51e..ce7b2e17e0acb0d50f2f125c21ed5f67178c7862 100755 (executable)
@@ -2,9 +2,9 @@
 set -eu
 
 SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
-FREQTRADE_CONFIG="${SCRIPT_DIR}/user_data/config.json"
-LOCAL_DOCKER_IMAGE="reforcexy-freqtrade"
-REMOTE_DOCKER_IMAGE="freqtradeorg/freqtrade:stable_freqairl"
+FREQTRADE_CONFIG="${FREQTRADE_CONFIG:-$SCRIPT_DIR}/user_data/config.json}"
+LOCAL_DOCKER_IMAGE="${LOCAL_DOCKER_IMAGE:-reforcexy-freqtrade}"
+REMOTE_DOCKER_IMAGE="${REMOTE_DOCKER_IMAGE:-freqtradeorg/freqtrade:stable_freqairl}"
 
 ################################
 
@@ -208,7 +208,7 @@ if [ ! -f "${SCRIPT_DIR}/docker-compose.yml" ] && [ ! -f "${SCRIPT_DIR}/docker-c
 fi
 
 if [ ! -f "$FREQTRADE_CONFIG" ]; then
-  echo_timestamped "Error: ${FREQTRADE_CONFIG} file not found from current directory"
+  echo_timestamped "Error: ${FREQTRADE_CONFIG} file not found"
   exit 1
 fi
 
@@ -237,6 +237,9 @@ if [ "$rebuild_local_image" = true ]; then
   echo_timestamped "Info: $message"
   send_telegram_message "$message"
   cd -- "$SCRIPT_DIR" || exit 1
+  if ! command docker compose pull --quiet >/dev/null 2>&1; then
+    echo_timestamped "Warning: docker compose pull failed"
+  fi
   if ! command docker compose --progress quiet down; then
     echo_timestamped "Error: docker compose down failed"
     exit 1