Continual learning trains an independent copy of the deployed policy with its
fitted feature pipeline. DQN/QRDQN deployments each persist their replay buffer;
it is loaded only when continual training starts. Missing or incompatible replay
-data prevents continuation but does not prevent inference. Reset trained models
-or use a new `freqai.identifier` to migrate incompatible artifacts, including
-deployments without the chronological training marker. Training disables
-`shuffle_after_split`. HPO studies and saved best parameters are reused only
-when their objective identity matches.
+data prevents continuation but does not prevent inference. The deployment
+generation covers frozen feature coordinates and PBRS reward semantics. Older
+generations, including `chronological-frozen-pipelines-v2`, remain usable for
+inference but cannot continue training. Reset trained models or use a new
+`freqai.identifier` to migrate. Training disables `shuffle_after_split`. HPO
+studies and saved best parameters are reused only when their objective identity
+matches.
Backtests continue only from a saved policy whose training cutoff precedes
the current window's end and its last available candle boundary. A later
discarded-row count; valid duplicates retain the same precedence.
See the model docstrings for continuation, HPO and statistics details.
+An expired model closes only open positions for the current pair, using each
+position's own side; positions for other pairs cannot generate its exit signals.
+
With `hold_potential_enabled=true`, ReforceXY enables `add_state_info` before
constructing environments so training and inference use the same observations.
Freqtrade does not support these state observations in backtesting; disable hold
return. These diagnostics do not change the training reward or realized capital.
Rewards combine the fill-time base components with a potential-based shaping
delta over the returned next observation. Termination liquidates any remaining
-position once and clears the terminal potential. `get_env_history()` returns one
+position once and sets terminal shaping to `-prev_potential`, even for tiny
+nonzero potentials. `get_env_history()` returns one
metrics/price row per transition. Its `execution_tick` is the transition/action/fill
key before the tick increment; its `tick` is the returned post-increment price and
observation row (normally `execution_tick + 1`). Exit-efficiency extrema include
a guarantee about fitted policies: theoretical invariance also requires an
observable state potential, the learner's discount, and appropriate boundaries.
-An absent learner `gamma` uses the canonical discount. An effective `gamma: null`
-is rejected before constructing or replacing environments. Validation follows
-HPO overrides and the resumed learner's gamma, so a valid higher-priority value
-can supersede a null base value. Learner and environment receive the same
-effective discount.
+An absent configured `gamma` uses the canonical discount. The effective discount
+must be a finite Python/NumPy integer or floating scalar in `[0, 1]`, normalized
+to a Python float. Null, booleans, strings, complex values and arrays are rejected
+before constructing or replacing environments. Validation follows HPO overrides
+and the resumed learner's gamma, so a valid higher-priority value can supersede
+an invalid base value. A persisted learner with missing or invalid gamma cannot
+continue training. Learner and environment use the same effective discount.
The corrected reward objective invalidates persisted HPO studies and best
parameters from the previous objective identity; incompatible studies are reset
and stale best-parameter payloads are ignored rather than warm-started.
ReforceXY additionally runs once with `FREQAI_QA_SHUFFLE_SEED=1`. This permutes
methods within test classes, not module or class order. `QaTestCase` restores the
action-mask cache and the Python, NumPy and CPU Torch RNG states before and after
-each test. Tests must isolate other mutable state themselves; the alternate order
-does not prove the absence of all global-state leaks.
+each test. Lifecycle probes cover successful cases, body failures and setup or
+teardown errors. Tests must isolate other mutable state themselves; the alternate
+order does not prove the absence of all global-state leaks.
The ReforceXY gate measures **only `ReforceXY/user_data`**, with branch coverage
and non-imported namespace files included. Tests, the analytical package and
},
{
"endCharacter": 22,
- "endLine": 1017,
+ "endLine": 1025,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Cannot assign to attribute \"train_env\" for class \"ReforceXY*\"\n Expression of type \"VecEnv\" cannot be assigned to attribute \"train_env\" of class \"ReforceXY\"\n Type \"VecEnv\" is not assignable to type \"VecMonitor | SubprocVecEnv | Env[Unknown, Unknown]\"\n \"VecEnv\" is not assignable to \"VecMonitor\"\n \"VecEnv\" is not assignable to \"SubprocVecEnv\"\n \"VecEnv\" is not assignable to \"Env[Unknown, Unknown]\"",
"rule": "reportAttributeAccessIssue",
"severity": "error",
"startCharacter": 13,
- "startLine": 1017
+ "startLine": 1025
},
{
"endCharacter": 37,
- "endLine": 1017,
+ "endLine": 1025,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Cannot assign to attribute \"eval_env\" for class \"ReforceXY*\"\n Expression of type \"VecEnv | None\" cannot be assigned to attribute \"eval_env\" of class \"ReforceXY\"\n Type \"VecEnv | None\" is not assignable to type \"VecMonitor | SubprocVecEnv | Env[Unknown, Unknown]\"\n Type \"VecEnv\" is not assignable to type \"VecMonitor | SubprocVecEnv | Env[Unknown, Unknown]\"\n \"VecEnv\" is not assignable to \"VecMonitor\"\n \"VecEnv\" is not assignable to \"SubprocVecEnv\"\n \"VecEnv\" is not assignable to \"Env[Unknown, Unknown]\"",
"rule": "reportAttributeAccessIssue",
"severity": "error",
"startCharacter": 29,
- "startLine": 1017
+ "startLine": 1025
},
{
"endCharacter": 24,
- "endLine": 1276,
+ "endLine": 1284,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"VecEnv\" cannot be assigned to parameter \"eval_env\" of type \"BaseEnvironment\" in function \"__init__\"\n \"VecEnv\" is not assignable to \"BaseEnvironment\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 16,
- "startLine": 1276
+ "startLine": 1284
},
{
"endCharacter": 38,
- "endLine": 1504,
+ "endLine": 1517,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"obj\" of type \"Sized\" in function \"len\"\n Type \"Any | None\" is not assignable to type \"Sized\"\n \"None\" is incompatible with protocol \"Sized\"\n \"__len__\" is not present",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 30,
- "startLine": 1504
+ "startLine": 1517
},
{
"endCharacter": 36,
- "endLine": 1508,
+ "endLine": 1521,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"obj\" of type \"Sized\" in function \"len\"\n Type \"Any | None\" is not assignable to type \"Sized\"\n \"None\" is incompatible with protocol \"Sized\"\n \"__len__\" is not present",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 29,
- "startLine": 1508
+ "startLine": 1521
},
{
"endCharacter": 80,
- "endLine": 1511,
+ "endLine": 1524,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"timeframe\" of type \"str\" in function \"steps_to_days\"\n Type \"Any | None\" is not assignable to type \"str\"\n \"None\" is not assignable to \"str\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 52,
- "startLine": 1511
+ "startLine": 1524
},
{
"endCharacter": 78,
- "endLine": 1512,
+ "endLine": 1525,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"timeframe\" of type \"str\" in function \"steps_to_days\"\n Type \"Any | None\" is not assignable to type \"str\"\n \"None\" is not assignable to \"str\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 50,
- "startLine": 1512
+ "startLine": 1525
},
{
"endCharacter": 80,
- "endLine": 1513,
+ "endLine": 1526,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"timeframe\" of type \"str\" in function \"steps_to_days\"\n Type \"Any | None\" is not assignable to type \"str\"\n \"None\" is not assignable to \"str\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 52,
- "startLine": 1513
+ "startLine": 1526
},
{
"endCharacter": 56,
- "endLine": 1599,
+ "endLine": 1610,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"VecMonitor | SubprocVecEnv | Env[Unknown, Unknown]\" cannot be assigned to parameter \"eval_env\" of type \"VecEnv | None\" in function \"get_callbacks\"\n Type \"VecMonitor | SubprocVecEnv | Env[Unknown, Unknown]\" is not assignable to type \"VecEnv | None\"\n Type \"Env[Unknown, Unknown]\" is not assignable to type \"VecEnv | None\"\n \"Env[Unknown, Unknown]\" is not assignable to \"VecEnv\"\n \"Env[Unknown, Unknown]\" is not assignable to \"None\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 43,
- "startLine": 1599
+ "startLine": 1610
},
{
"endCharacter": 84,
- "endLine": 1619,
+ "endLine": 1630,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"float | list[float]\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"float | list[float]\" is not assignable to type \"ConvertibleToFloat\"\n Type \"list[float]\" is not assignable to type \"ConvertibleToFloat\"\n \"list[float]\" is not assignable to \"str\"\n \"list[float]\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"list[float]\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"list[float]\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 67,
- "startLine": 1619
+ "startLine": 1630
},
{
"endCharacter": 84,
- "endLine": 1619,
+ "endLine": 1630,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"float | list[float]\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"float | list[float]\" is not assignable to type \"ConvertibleToFloat\"\n Type \"list[float]\" is not assignable to type \"ConvertibleToFloat\"\n \"list[float]\" is not assignable to \"str\"\n \"list[float]\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"list[float]\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"list[float]\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 67,
- "startLine": 1619
+ "startLine": 1630
},
{
"endCharacter": 44,
- "endLine": 2693,
+ "endLine": 2704,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "\"best_trial_params\" is possibly unbound",
"rule": "reportPossiblyUnboundVariable",
"severity": "error",
"startCharacter": 27,
- "startLine": 2693
+ "startLine": 2704
},
{
"endCharacter": 12,
- "endLine": 2713,
+ "endLine": 2724,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Parameter declaration \"seed\" is obscured by a declaration of the same name",
"rule": "reportRedeclaration",
"severity": "error",
"startCharacter": 8,
- "startLine": 2713
+ "startLine": 2724
},
{
"endCharacter": 16,
- "endLine": 2714,
+ "endLine": 2725,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Parameter declaration \"env_info\" is obscured by a declaration of the same name",
"rule": "reportRedeclaration",
"severity": "error",
"startCharacter": 8,
- "startLine": 2714
+ "startLine": 2725
},
{
"endCharacter": 51,
- "endLine": 2757,
+ "endLine": 2768,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"list[() -> BaseEnvironment]\" cannot be assigned to parameter \"env_fns\" of type \"list[() -> Env[Unknown, Unknown]]\" in function \"__init__\"\n \"list[() -> BaseEnvironment]\" is not assignable to \"list[() -> Env[Unknown, Unknown]]\"\n Type parameter \"_T@list\" is invariant, but \"() -> BaseEnvironment\" is not the same as \"() -> Env[Unknown, Unknown]\"\n Consider switching from \"list\" to \"Sequence\" which is covariant",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 42,
- "startLine": 2757
+ "startLine": 2768
},
{
"endCharacter": 53,
- "endLine": 2763,
+ "endLine": 2774,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"list[() -> BaseEnvironment]\" cannot be assigned to parameter \"env_fns\" of type \"list[() -> Env[Unknown, Unknown]]\" in function \"__init__\"\n \"list[() -> BaseEnvironment]\" is not assignable to \"list[() -> Env[Unknown, Unknown]]\"\n Type parameter \"_T@list\" is invariant, but \"() -> BaseEnvironment\" is not the same as \"() -> Env[Unknown, Unknown]\"\n Consider switching from \"list\" to \"Sequence\" which is covariant",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 45,
- "startLine": 2763
+ "startLine": 2774
},
{
"endCharacter": 22,
- "endLine": 2826,
+ "endLine": 2837,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Operator \"*\" not supported for \"None\"",
"rule": "reportOptionalOperand",
"severity": "error",
"startCharacter": 15,
- "startLine": 2826
+ "startLine": 2837
},
{
"endCharacter": 96,
- "endLine": 2828,
+ "endLine": 2839,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Operator \"*\" not supported for \"None\"",
"rule": "reportOptionalOperand",
"severity": "error",
"startCharacter": 89,
- "startLine": 2828
+ "startLine": 2839
},
{
"endCharacter": 23,
- "endLine": 2831,
+ "endLine": 2842,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Operator \"*\" not supported for \"None\"",
"rule": "reportOptionalOperand",
"severity": "error",
"startCharacter": 16,
- "startLine": 2831
+ "startLine": 2842
},
{
"endCharacter": 98,
- "endLine": 2833,
+ "endLine": 2844,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Operator \"*\" not supported for \"None\"",
"rule": "reportOptionalOperand",
"severity": "error",
"startCharacter": 91,
- "startLine": 2833
+ "startLine": 2844
},
{
"endCharacter": 44,
- "endLine": 2845,
+ "endLine": 2856,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Operator \"*\" not supported for types \"Any | None\" and \"Any | int | None\"\n Operator \"*\" not supported for types \"None\" and \"None\"\n Operator \"*\" not supported for types \"None\" and \"int\"",
"rule": "reportOperatorIssue",
"severity": "error",
"startCharacter": 15,
- "startLine": 2845
+ "startLine": 2856
},
{
"endCharacter": 133,
- "endLine": 2847,
+ "endLine": 2858,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Operator \"*\" not supported for types \"Any | None\" and \"Any | int | None\"\n Operator \"*\" not supported for types \"None\" and \"None\"\n Operator \"*\" not supported for types \"None\" and \"int\"",
"rule": "reportOperatorIssue",
"severity": "error",
"startCharacter": 106,
- "startLine": 2847
+ "startLine": 2858
},
{
"endCharacter": 30,
- "endLine": 2850,
+ "endLine": 2861,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Operator \">\" not supported for \"None\"",
"rule": "reportOptionalOperand",
"severity": "error",
"startCharacter": 15,
- "startLine": 2850
+ "startLine": 2861
},
{
"endCharacter": 54,
- "endLine": 2916,
+ "endLine": 2927,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "\"is_pruned\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 45,
- "startLine": 2916
+ "startLine": 2927
},
{
"endCharacter": 67,
- "endLine": 2919,
+ "endLine": 2930,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "\"use_masking\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 56,
- "startLine": 2919
+ "startLine": 2930
},
{
"endCharacter": 60,
- "endLine": 2927,
+ "endLine": 2938,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "\"update_best_reward\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 42,
- "startLine": 2927
+ "startLine": 2938
},
{
"endCharacter": 84,
- "endLine": 2927,
+ "endLine": 2938,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"float | list[float]\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"float | list[float]\" is not assignable to type \"ConvertibleToFloat\"\n Type \"list[float]\" is not assignable to type \"ConvertibleToFloat\"\n \"list[float]\" is not assignable to \"str\"\n \"list[float]\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"list[float]\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"list[float]\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 67,
- "startLine": 2927
+ "startLine": 2938
},
{
"endCharacter": 84,
- "endLine": 2927,
+ "endLine": 2938,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"float | list[float]\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"float | list[float]\" is not assignable to type \"ConvertibleToFloat\"\n Type \"list[float]\" is not assignable to type \"ConvertibleToFloat\"\n \"list[float]\" is not assignable to \"str\"\n \"list[float]\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"list[float]\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"list[float]\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 67,
- "startLine": 2927
+ "startLine": 2938
},
{
"endCharacter": 46,
- "endLine": 2981,
+ "endLine": 2992,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "\"is_pruned\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 37,
- "startLine": 2981
+ "startLine": 2992
},
{
"endCharacter": 57,
- "endLine": 2984,
+ "endLine": 2995,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "\"best_mean_reward\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 41,
- "startLine": 2984
+ "startLine": 2995
},
{
"endCharacter": 37,
- "endLine": 2994,
+ "endLine": 3005,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Cannot assign to attribute \"train_env\" for class \"ReforceXY*\"\n Type \"None\" is not assignable to type \"VecMonitor | SubprocVecEnv | Env[Unknown, Unknown]\"\n \"None\" is not assignable to \"VecMonitor\"\n \"None\" is not assignable to \"SubprocVecEnv\"\n \"None\" is not assignable to \"Env[Unknown, Unknown]\"",
"rule": "reportAttributeAccessIssue",
"severity": "error",
"startCharacter": 33,
- "startLine": 2994
+ "startLine": 3005
},
{
"endCharacter": 36,
- "endLine": 2999,
+ "endLine": 3010,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Cannot assign to attribute \"eval_env\" for class \"ReforceXY*\"\n Type \"None\" is not assignable to type \"VecMonitor | SubprocVecEnv | Env[Unknown, Unknown]\"\n \"None\" is not assignable to \"VecMonitor\"\n \"None\" is not assignable to \"SubprocVecEnv\"\n \"None\" is not assignable to \"Env[Unknown, Unknown]\"",
"rule": "reportAttributeAccessIssue",
"severity": "error",
"startCharacter": 32,
- "startLine": 2999
+ "startLine": 3010
},
{
"endCharacter": 7,
- "endLine": 3044,
+ "endLine": 3055,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Declaration \"MyRLEnv\" is obscured by a declaration of the same name",
"rule": "reportRedeclaration",
"severity": "error",
"startCharacter": 0,
- "startLine": 3044
+ "startLine": 3055
},
{
"endCharacter": 36,
- "endLine": 3056,
+ "endLine": 3067,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Declaration \"_last_closed_trade_tick\" is obscured by a declaration of the same name",
"rule": "reportRedeclaration",
"severity": "error",
"startCharacter": 13,
- "startLine": 3056
+ "startLine": 3067
},
{
"endCharacter": 13,
- "endLine": 3644,
+ "endLine": 3659,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Method \"reset\" overrides class \"BaseEnvironment\" in an incompatible manner\n Return type mismatch: base method returns type \"tuple[DataFrame, dict[Unknown, Unknown]]\", override returns type \"tuple[NDArray[float32], dict[str, Any]]\"\n \"tuple[NDArray[float32], dict[str, Any]]\" is not assignable to \"tuple[DataFrame, dict[Unknown, Unknown]]\"\n Tuple entry 1 is incorrect type\n \"ndarray[_AnyShape, dtype[float32]]\" is not assignable to \"DataFrame\"",
"rule": "reportIncompatibleMethodOverride",
"severity": "error",
"startCharacter": 8,
- "startLine": 3644
+ "startLine": 3659
},
{
"endCharacter": 26,
- "endLine": 3665,
+ "endLine": 3680,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Type \"tuple[DataFrame, dict[Unknown, Unknown]]\" is not assignable to return type \"tuple[NDArray[float32], dict[str, Any]]\"\n \"DataFrame\" is not assignable to \"ndarray[_AnyShape, dtype[float32]]\"",
"rule": "reportReturnType",
"severity": "error",
"startCharacter": 15,
- "startLine": 3665
+ "startLine": 3680
},
{
"endCharacter": 55,
- "endLine": 3973,
+ "endLine": 3988,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 44,
- "startLine": 3973
+ "startLine": 3988
},
{
"endCharacter": 55,
- "endLine": 3973,
+ "endLine": 3988,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 44,
- "startLine": 3973
+ "startLine": 3988
},
{
"endCharacter": 59,
- "endLine": 3997,
+ "endLine": 4012,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 48,
- "startLine": 3997
+ "startLine": 4012
},
{
"endCharacter": 59,
- "endLine": 3997,
+ "endLine": 4012,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 48,
- "startLine": 3997
+ "startLine": 4012
},
{
"endCharacter": 24,
- "endLine": 4026,
+ "endLine": 4041,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Method \"_get_observation\" overrides class \"BaseEnvironment\" in an incompatible manner\n Return type mismatch: base method returns type \"DataFrame\", override returns type \"NDArray[float32]\"\n \"ndarray[_AnyShape, dtype[float32]]\" is not assignable to \"DataFrame\"",
"rule": "reportIncompatibleMethodOverride",
"severity": "error",
"startCharacter": 8,
- "startLine": 4026
+ "startLine": 4041
},
{
"endCharacter": 12,
- "endLine": 4128,
+ "endLine": 4134,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Method \"step\" overrides class \"Base5ActionRLEnv\" in an incompatible manner\n Return type mismatch: base method returns type \"tuple[DataFrame, float, bool, Literal[False], dict[str, Unknown]]\", override returns type \"tuple[NDArray[float32], float, bool, bool, dict[str, Any]]\"\n \"tuple[NDArray[float32], float, bool, bool, dict[str, Any]]\" is not assignable to \"tuple[DataFrame, float, bool, Literal[False], dict[str, Unknown]]\"\n Tuple entry 1 is incorrect type\n \"ndarray[_AnyShape, dtype[float32]]\" is not assignable to \"DataFrame\"",
"rule": "reportIncompatibleMethodOverride",
"severity": "error",
"startCharacter": 8,
- "startLine": 4128
+ "startLine": 4134
},
{
"endCharacter": 20,
- "endLine": 4318,
+ "endLine": 4324,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Method \"action_masks\" overrides class \"BaseEnvironment\" in an incompatible manner\n Return type mismatch: base method returns type \"list[bool]\", override returns type \"NDArray[bool_]\"\n \"ndarray[_AnyShape, dtype[bool_]]\" is not assignable to \"list[bool]\"",
"rule": "reportIncompatibleMethodOverride",
"severity": "error",
"startCharacter": 8,
- "startLine": 4318
+ "startLine": 4324
},
{
"endCharacter": 40,
- "endLine": 4467,
+ "endLine": 4473,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "\"Figure\" is not exported from module \"matplotlib.pyplot\"",
"rule": "reportPrivateImportUsage",
"severity": "error",
"startCharacter": 34,
- "startLine": 4467
+ "startLine": 4473
},
{
"endCharacter": 54,
- "endLine": 4970,
+ "endLine": 4976,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 45,
- "startLine": 4970
+ "startLine": 4976
},
{
"endCharacter": 54,
- "endLine": 4970,
+ "endLine": 4976,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 45,
- "startLine": 4970
+ "startLine": 4976
},
{
"endCharacter": 50,
- "endLine": 4982,
+ "endLine": 4988,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"object\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"object\" is not assignable to type \"ConvertibleToFloat\"\n \"object\" is not assignable to \"str\"\n \"object\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"object\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"object\" is incompatible with protocol \"SupportsIndex\"\n \"__index__\" is not present",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 37,
- "startLine": 4982
+ "startLine": 4988
},
{
"endCharacter": 72,
- "endLine": 4993,
+ "endLine": 4999,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 70,
- "startLine": 4993
+ "startLine": 4999
},
{
"endCharacter": 72,
- "endLine": 4993,
+ "endLine": 4999,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 70,
- "startLine": 4993
+ "startLine": 4999
},
{
"endCharacter": 73,
- "endLine": 5002,
+ "endLine": 5008,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 71,
- "startLine": 5002
+ "startLine": 5008
},
{
"endCharacter": 73,
- "endLine": 5002,
+ "endLine": 5008,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"float | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"float | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 71,
- "startLine": 5002
+ "startLine": 5008
},
{
"endCharacter": 58,
- "endLine": 5011,
+ "endLine": 5017,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 56,
- "startLine": 5011
+ "startLine": 5017
},
{
"endCharacter": 58,
- "endLine": 5011,
+ "endLine": 5017,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 56,
- "startLine": 5011
+ "startLine": 5017
},
{
"endCharacter": 50,
- "endLine": 5242,
+ "endLine": 5248,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Mapping[Unknown, Unknown]\" cannot be assigned to parameter \"src\" of type \"dict[str, Any]\" in function \"deepmerge\"\n \"Mapping[Unknown, Unknown]\" is not assignable to \"dict[str, Any]\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 49,
- "startLine": 5242
+ "startLine": 5248
},
{
"endCharacter": 20,
- "endLine": 5419,
+ "endLine": 5425,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 18,
- "startLine": 5419
+ "startLine": 5425
},
{
"endCharacter": 20,
- "endLine": 5419,
+ "endLine": 5425,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 18,
- "startLine": 5419
+ "startLine": 5425
},
{
"endCharacter": 59,
- "endLine": 5424,
+ "endLine": 5430,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 31,
- "startLine": 5424
+ "startLine": 5430
},
{
"endCharacter": 59,
- "endLine": 5424,
+ "endLine": 5430,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 31,
- "startLine": 5424
+ "startLine": 5430
},
{
"endCharacter": 65,
- "endLine": 5425,
+ "endLine": 5431,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 34,
- "startLine": 5425
+ "startLine": 5431
},
{
"endCharacter": 65,
- "endLine": 5425,
+ "endLine": 5431,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 34,
- "startLine": 5425
- },
- {
- "endCharacter": 57,
- "endLine": 5426,
- "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
- "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
- "rule": "reportArgumentType",
- "severity": "error",
- "startCharacter": 31,
- "startLine": 5426
- },
- {
- "endCharacter": 57,
- "endLine": 5426,
- "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
- "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
- "rule": "reportArgumentType",
- "severity": "error",
- "startCharacter": 31,
- "startLine": 5426
+ "startLine": 5431
},
{
"endCharacter": 63,
- "endLine": 5428,
+ "endLine": 5434,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 34,
- "startLine": 5428
+ "startLine": 5434
},
{
"endCharacter": 63,
- "endLine": 5428,
+ "endLine": 5434,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 34,
- "startLine": 5428
+ "startLine": 5434
},
{
"endCharacter": 61,
- "endLine": 5430,
+ "endLine": 5436,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 32,
- "startLine": 5430
+ "startLine": 5436
},
{
"endCharacter": 61,
- "endLine": 5430,
+ "endLine": 5436,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 32,
- "startLine": 5430
+ "startLine": 5436
},
{
"endCharacter": 67,
- "endLine": 5431,
+ "endLine": 5437,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 36,
- "startLine": 5431
+ "startLine": 5437
},
{
"endCharacter": 67,
- "endLine": 5431,
+ "endLine": 5437,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 36,
- "startLine": 5431
+ "startLine": 5437
},
{
"endCharacter": 73,
- "endLine": 5432,
+ "endLine": 5438,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 39,
- "startLine": 5432
+ "startLine": 5438
},
{
"endCharacter": 73,
- "endLine": 5432,
+ "endLine": 5438,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 39,
- "startLine": 5432
+ "startLine": 5438
},
{
"endCharacter": 61,
- "endLine": 5433,
+ "endLine": 5439,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 33,
- "startLine": 5433
+ "startLine": 5439
},
{
"endCharacter": 61,
- "endLine": 5433,
+ "endLine": 5439,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 33,
- "startLine": 5433
+ "startLine": 5439
},
{
"endCharacter": 89,
- "endLine": 5440,
+ "endLine": 5446,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 52,
- "startLine": 5440
+ "startLine": 5446
},
{
"endCharacter": 89,
- "endLine": 5440,
+ "endLine": 5446,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 52,
- "startLine": 5440
+ "startLine": 5446
},
{
"endCharacter": 83,
- "endLine": 5441,
+ "endLine": 5447,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 49,
- "startLine": 5441
+ "startLine": 5447
},
{
"endCharacter": 83,
- "endLine": 5441,
+ "endLine": 5447,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 49,
- "startLine": 5441
- },
- {
- "endCharacter": 57,
- "endLine": 5466,
- "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
- "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
- "rule": "reportArgumentType",
- "severity": "error",
- "startCharacter": 31,
- "startLine": 5466
- },
- {
- "endCharacter": 57,
- "endLine": 5466,
- "file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
- "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
- "rule": "reportArgumentType",
- "severity": "error",
- "startCharacter": 31,
- "startLine": 5466
+ "startLine": 5447
},
{
"endCharacter": 65,
- "endLine": 5467,
+ "endLine": 5473,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 34,
- "startLine": 5467
+ "startLine": 5473
},
{
"endCharacter": 65,
- "endLine": 5467,
+ "endLine": 5473,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 34,
- "startLine": 5467
+ "startLine": 5473
},
{
"endCharacter": 67,
- "endLine": 5469,
+ "endLine": 5475,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 35,
- "startLine": 5469
+ "startLine": 5475
},
{
"endCharacter": 67,
- "endLine": 5469,
+ "endLine": 5475,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 35,
- "startLine": 5469
+ "startLine": 5475
},
{
"endCharacter": 87,
- "endLine": 5472,
+ "endLine": 5478,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 46,
- "startLine": 5472
+ "startLine": 5478
},
{
"endCharacter": 87,
- "endLine": 5472,
+ "endLine": 5478,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 46,
- "startLine": 5472
+ "startLine": 5478
},
{
"endCharacter": 93,
- "endLine": 5473,
+ "endLine": 5479,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 49,
- "startLine": 5473
+ "startLine": 5479
},
{
"endCharacter": 93,
- "endLine": 5473,
+ "endLine": 5479,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 49,
- "startLine": 5473
+ "startLine": 5479
},
{
"endCharacter": 89,
- "endLine": 5474,
+ "endLine": 5480,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 47,
- "startLine": 5474
+ "startLine": 5480
},
{
"endCharacter": 89,
- "endLine": 5474,
+ "endLine": 5480,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToFloat\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToFloat\"\n Type \"None\" is not assignable to type \"ConvertibleToFloat\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsFloat\"\n \"__float__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 47,
- "startLine": 5474
+ "startLine": 5480
},
{
"endCharacter": 89,
- "endLine": 5475,
+ "endLine": 5481,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 46,
- "startLine": 5475
+ "startLine": 5481
},
{
"endCharacter": 89,
- "endLine": 5475,
+ "endLine": 5481,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 46,
- "startLine": 5475
+ "startLine": 5481
},
{
"endCharacter": 75,
- "endLine": 5476,
+ "endLine": 5482,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 39,
- "startLine": 5476
+ "startLine": 5482
},
{
"endCharacter": 75,
- "endLine": 5476,
+ "endLine": 5482,
"file": "ReforceXY/user_data/freqaimodels/ReforceXY.py",
"message": "Argument of type \"Any | None\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n Type \"Any | None\" is not assignable to type \"ConvertibleToInt\"\n Type \"None\" is not assignable to type \"ConvertibleToInt\"\n \"None\" is not assignable to \"str\"\n \"None\" is incompatible with protocol \"Buffer\"\n \"__buffer__\" is not present\n \"None\" is incompatible with protocol \"SupportsInt\"\n \"__int__\" is not present\n \"None\" is incompatible with protocol \"SupportsIndex\"\n ...",
"rule": "reportArgumentType",
"severity": "error",
"startCharacter": 39,
- "startLine": 5476
+ "startLine": 5482
},
{
"endCharacter": 33,
show_missing = True
precision = 1
include_namespace_packages = True
-# measured 2026-10-02 at 75.3% — raise only, never lower
+# measured 2026-10-02 at 75.6% — raise only, never lower
fail_under = 70
\ No newline at end of file
"check_envs": False,
"add_state_info": False,
},
- # `create_sampler` resolves `auto` through optunahub.load_module, which is an
- # outbound fetch to hub.optuna.org, so the sampler is pinned here. The pin holds
- # only while callers go through `**overrides`: two tests assign `rl_config_optuna`
- # wholesale and would discard it. The guarantee that survives that is in the
- # production default — `create_sampler` falls back to "tpe" and raises for anything
- # outside `_Samplers`, so no config value reaches the network either way. There is
- # no `pruner` key: `create_pruner` is a staticmethod taking three ints.
+ # Use local TPE by default in QA. Explicit overrides are preserved; `auto`
+ # loads an OptunaHub sampler and may require network access.
"rl_config_optuna": {"enabled": False, "sampler": "tpe"},
},
}
import math
import tempfile
import unittest
+from pathlib import Path
from types import SimpleNamespace
+from unittest import mock
import numpy as np
import pandas as pd
from qa_support import QaTestCase, model_config
from sb3_contrib import MaskablePPO
+from sb3_contrib.common.maskable.evaluation import evaluate_policy
from ReforceXY.user_data.freqaimodels.ReforceXY import Actions, MyRLEnv, Positions, ReforceXY
self.assertNotEqual(additive, 0.0)
self.assertEqual(info["pbrs_invariant"], mode == "canonical")
+ def test_tiny_terminal_potentials_reconcile_reward_history_and_discounted_sum(self):
+ for mode, explicit_exit in (
+ ("canonical", False),
+ ("retain_previous", False),
+ ("retain_previous", True),
+ ):
+ with self.subTest(mode=mode, explicit_exit=explicit_exit):
+ shaped = self.env(fee=0.0015, hold_potential_ratio=1e-10, exit_potential_mode=mode)
+ base = self.env(fee=0.0015, hold_potential_enabled=False, exit_potential_mode=mode)
+ shaping = []
+ for tick in range(20):
+ action = Actions.Long_enter if tick == 0 else Actions.Neutral
+ if explicit_exit and tick == 2:
+ action = Actions.Long_exit
+ _, reward, done, truncated, _ = shaped.step(action.value)
+ _, base_reward, base_done, base_truncated, _ = base.step(action.value)
+ self.assertEqual((done, truncated), (base_done, base_truncated))
+ expected = 0.8 * shaped._last_next_potential - shaped._last_prev_potential
+ self.assertEqual(shaped._last_reward_shaping, expected)
+ self.assertAlmostEqual(reward - base_reward, expected, places=14)
+ shaping.append(expected)
+ if done or truncated:
+ break
+ self.assertTrue(done or truncated)
+ self.assertGreater(abs(shaped._last_prev_potential), 0.0)
+ self.assertLess(abs(shaped._last_prev_potential), 1e-8)
+ self.assertEqual(shaped._last_next_potential, 0.0)
+ self.assertEqual(shaped._last_reward_shaping, -shaped._last_prev_potential)
+ self.assertAlmostEqual(
+ math.fsum(0.8**t * f for t, f in enumerate(shaping)), 0.0, places=20
+ )
+ self.assertAlmostEqual(shaped._total_reward_shaping, math.fsum(shaping), places=20)
+ self.assertEqual(len(shaped.trade_history), 2)
+ history = shaped.get_env_history()
+ self.assertEqual(history.iloc[-1]["reward_shaping"], -shaped._last_prev_potential)
+ self.assertEqual(history.iloc[-1]["next_potential"], 0.0)
+
+ def test_standalone_environment_rejects_invalid_potential_discounts(self):
+ for gamma in (None, math.nan, math.inf, -math.inf, -0.1, 1.1, True, "0.8"):
+ with self.subTest(gamma=gamma), self.assertRaises(ValueError):
+ self.env(potential_gamma=gamma)
+
def test_reset_discards_the_previous_episode_potential_and_additive_totals(self):
env = self.env(
exit_potential_mode="retain_previous", entry_additive_enabled=True, fee=0.0015
with self.assertRaises(ValueError):
model.pack_env_dict("BTC/USDT", {"gamma": None})
+ def test_effective_discount_requires_a_finite_real_scalar_in_unit_interval(self):
+ model = self.model(gamma=0.83)
+ for gamma in (
+ math.nan,
+ math.inf,
+ -math.inf,
+ -0.1,
+ 1.1,
+ True,
+ np.bool_(False),
+ "0.8",
+ 0.8 + 0j,
+ [0.8],
+ np.array(0.8),
+ np.nextafter(np.longdouble(1), np.longdouble(math.inf)),
+ ):
+ with self.subTest(gamma=gamma), self.assertRaises(ValueError):
+ model.pack_env_dict("BTC/USDT", {"gamma": gamma})
+ for gamma in (0, 1, np.int64(1), np.float32(0.79), np.float64(0.83)):
+ with self.subTest(gamma=gamma):
+ kwargs = model.pack_env_dict("BTC/USDT", {"gamma": gamma})
+ resolved = kwargs["config"]["freqai"]["rl_config"]["model_reward_parameters"][
+ "potential_gamma"
+ ]
+ self.assertIs(type(resolved), float)
+ self.assertEqual(resolved, float(gamma))
+ prices = pd.DataFrame({"open": [100.0] * 16})
+ env = MyRLEnv(df=prices.copy(), prices=prices, **kwargs)
+ self.addCleanup(env.close)
+ learner = MaskablePPO(
+ "MlpPolicy",
+ env,
+ gamma=resolved,
+ n_steps=8,
+ batch_size=8,
+ n_epochs=1,
+ device="cpu",
+ )
+ learner.learn(8)
+ self.assertEqual(learner.gamma, env._potential_gamma)
+ self.assertGreater(learner._n_updates, 0)
+
def test_invalid_replacement_discount_does_not_close_running_environments(self):
model = self.model(gamma=0.83)
features = pd.DataFrame({"f": np.arange(16, dtype=float)})
model.set_train_and_eval_environments(data, prices, prices, kitchen)
running_train, running_eval = model.train_env, model.eval_env
first = running_train.reset()
- with self.assertRaises(ValueError):
- model.set_train_and_eval_environments(data, prices, prices, kitchen, {"gamma": None})
+ for gamma in (None, math.nan, math.inf, -math.inf, -0.1, 1.1, True, "0.8"):
+ with self.subTest(gamma=gamma), self.assertRaises(ValueError):
+ model.set_train_and_eval_environments(
+ data, prices, prices, kitchen, {"gamma": gamma}
+ )
+ self.assertIs(model.train_env, running_train)
+ self.assertIs(model.eval_env, running_eval)
self.assertIs(model.train_env, running_train)
self.assertIs(model.eval_env, running_eval)
second, _, done, _ = running_train.step([Actions.Neutral.value])
self.assertEqual(learner.gamma, env._potential_gamma)
self.assertGreater(learner._n_updates, 0)
+ def test_persisted_numpy_learner_discount_overrides_finite_and_null_base(self):
+ with tempfile.TemporaryDirectory() as temp:
+ gamma = np.float32(0.79)
+ prices = pd.DataFrame({"open": [100.0] * 16})
+ for base in (0.95, None):
+ with self.subTest(base=base):
+ owner = self.model(gamma=base)
+ kwargs = owner.pack_env_dict("BTC/USDT", {"gamma": gamma})
+ env = MyRLEnv(df=prices.copy(), prices=prices, **kwargs)
+ self.addCleanup(env.close)
+ learner = MaskablePPO(
+ "MlpPolicy",
+ env,
+ gamma=gamma,
+ n_steps=8,
+ batch_size=8,
+ n_epochs=1,
+ device="cpu",
+ )
+ learner.learn(8)
+ archive = Path(temp) / f"learner-{base}"
+ learner.save(archive)
+ loaded = MaskablePPO.load(archive)
+ self.assertIsInstance(loaded.gamma, np.floating)
+ previous_updates = loaded._n_updates
+ observed = []
+
+ def evaluate(policy, environment, observed=observed, **parameters):
+ observed.append(
+ (
+ policy.gamma,
+ policy.get_env().get_attr("_potential_gamma"),
+ environment.get_attr("_potential_gamma"),
+ )
+ )
+ return evaluate_policy(policy, environment, **parameters)
+
+ data = {"train_features": prices.copy(), "test_features": prices.copy()}
+ kitchen = SimpleNamespace(pair="BTC/USDT", data_path=Path(temp) / f"fit-{base}")
+ kitchen.data_path.mkdir()
+ with mock.patch(
+ "ReforceXY.user_data.freqaimodels.ReforceXY.evaluate_policy",
+ side_effect=evaluate,
+ ):
+ continued = owner.fit(
+ data,
+ kitchen,
+ prices_train=prices,
+ prices_test=prices,
+ deployment_state=(loaded, None),
+ )
+ self.assertEqual(observed, [(gamma, [float(gamma)], [float(gamma)])])
+ self.assertEqual(float(continued.gamma), float(gamma))
+ self.assertGreater(loaded._n_updates, previous_updates)
+
if __name__ == "__main__":
unittest.main()
"""Regression contracts for learning eligibility, replay and temporal observations."""
+import json
import tempfile
from pathlib import Path
from types import SimpleNamespace
from freqtrade.enums import RunMode
from freqtrade.exceptions import DependencyException
from freqtrade.exchange import timeframe_to_seconds
-from freqtrade.freqai.data_drawer import FreqaiDataDrawer
+from freqtrade.freqai.data_drawer import METADATA, FreqaiDataDrawer
from freqtrade.freqai.data_kitchen import FreqaiDataKitchen
from optuna import TrialPruned, create_study
from qa_support import QaTestCase, RecordingPolicy, model_config
np.testing.assert_array_equal(trained.replay_buffer.observations, replay)
self.assertEqual(restored.replay_buffer.size(), 0)
self.assertIs(model.dd.load_data(dk.pair, dk), restored)
+ compatible, pipeline = model._resolve_deployment_state(dk, dk.pair)
+ previous_updates = compatible._n_updates
+ continued_dk = FreqaiDataKitchen(config, live=True, pair=dk.pair)
+ continued_dk.data_path = Path(temp) / "continued"
+ continued_dk.data_path.mkdir()
+ model.fit(
+ dk.data_dictionary,
+ continued_dk,
+ prices_train=dk.data_dictionary["train_prices"],
+ prices_test=dk.data_dictionary["test_prices"],
+ deployment_state=(compatible, pipeline),
+ )
+ self.assertGreater(compatible._n_updates, previous_updates)
+ metadata_path = dk.data_path / f"{dk.model_filename}_{METADATA}.json"
+ metadata = json.loads(metadata_path.read_text())
+ current_generation = metadata[model._DEPLOYMENT_COORDINATE_MARKER_KEY]
+ metadata[model._DEPLOYMENT_COORDINATE_MARKER_KEY] = (
+ "chronological-frozen-pipelines-v2"
+ )
+ metadata_path.write_text(json.dumps(metadata))
+ for cached in (False, True):
+ with self.subTest(legacy_cached=cached):
+ model.dd.model_dictionary.clear()
+ model.dd.meta_data_dictionary.clear()
+ if cached:
+ inference = model.dd.load_data(dk.pair, dk)
+ action, _ = inference.predict(
+ np.zeros(inference.observation_space.shape, dtype=np.float32),
+ deterministic=True,
+ )
+ self.assertTrue(inference.action_space.contains(action))
+ with self.assertRaisesRegex(DependencyException, "Reset trained models"):
+ model._resolve_deployment_state(dk, dk.pair)
+ metadata[model._DEPLOYMENT_COORDINATE_MARKER_KEY] = current_generation
+ metadata_path.write_text(json.dumps(metadata))
+ model.dd.meta_data_dictionary.clear()
model.dd.model_dictionary.clear()
(dk.data_path / dk.data["reforcexy_replay"]).unlink()
inference_model = model.dd.load_data(dk.pair, dk)
import unittest
from datetime import datetime, timezone
-from types import SimpleNamespace
from unittest import mock
import numpy as np
self.assertFalse(_raised(result["exit_long"])[0])
self.assertFalse(_raised(result["exit_short"])[0])
- def test_a_rejected_prediction_closes_the_open_position_of_its_own_side(self):
- # do_predict == 2 is a rejected prediction: the open trade must be closed, and
- # its side decides which flag is set, not the recorded action.
- frame = _frame([1], do_predict=2)
- for is_short, expected in ((False, "exit_long"), (True, "exit_short")):
- with self.subTest(is_short=is_short):
- trade = SimpleNamespace(is_short=is_short)
- with mock.patch(
- "ReforceXY.user_data.strategies.RLAgentStrategy.Trade.get_trades_proxy",
- return_value=[trade],
- ):
- result = self._strategy().populate_exit_trend(
- frame.copy(), {"pair": "BTC/USDT"}
- )
- self.assertTrue(_raised(result[expected])[0])
- other = "exit_short" if expected == "exit_long" else "exit_long"
- self.assertFalse(_raised(result[other])[0])
-
- def test_a_rejected_prediction_ignores_closed_positions(self):
- # Reached through freqtrade's own backtest collections rather than by asserting
- # the call arguments, so a strategy that filtered differently would still pass.
- # With `is_open` dropped the proxy returns closed trades too, and this goes red.
- closed = SimpleNamespace(pair="BTC/USDT", is_open=False, is_short=False)
- opened = SimpleNamespace(pair="BTC/USDT", is_open=True, is_short=True)
- for open_trades, expected_short in (([], False), ([opened], True)):
- with self.subTest(open_short=expected_short):
+ def test_an_expired_model_closes_only_open_positions_for_the_current_pair(self):
+ closed = LocalTrade(pair="BTC/USDT", is_open=False, is_short=False)
+ long = LocalTrade(pair="BTC/USDT", is_open=True, is_short=False)
+ short = LocalTrade(pair="BTC/USDT", is_open=True, is_short=True)
+ unrelated_long = LocalTrade(pair="ETH/USDT", is_open=True, is_short=False)
+ unrelated_short = LocalTrade(pair="ETH/USDT", is_open=True, is_short=True)
+ for open_trades, expected in (
+ ([], (False, False)),
+ ([short], (False, True)),
+ ([long, unrelated_short], (True, False)),
+ ([short, unrelated_long], (False, True)),
+ ([unrelated_long], (False, False)),
+ ([unrelated_short], (False, False)),
+ ):
+ with self.subTest(expected=expected, trades=open_trades):
with (
mock.patch.object(Trade, "use_db", False),
mock.patch.object(LocalTrade, "bt_trades", [closed]),
mock.patch.object(LocalTrade, "bt_trades_open", open_trades),
):
result = self._strategy().populate_exit_trend(
- _frame([Actions.Neutral.value], do_predict=2),
- {"pair": "BTC/USDT"},
+ _frame([Actions.Neutral.value], do_predict=2), {"pair": "BTC/USDT"}
)
- self.assertEqual([False], _raised(result["exit_long"]))
- self.assertEqual([expected_short], _raised(result["exit_short"]))
+ self.assertEqual([expected[0]], _raised(result["exit_long"]))
+ self.assertEqual([expected[1]], _raised(result["exit_short"]))
def test_a_row_without_a_prediction_raises_no_exit(self):
result = self._strategy().populate_exit_trend(
self.assertEqual([False, False], _raised(result["exit_long"]))
self.assertEqual([False, False], _raised(result["exit_short"]))
- def test_a_rejected_prediction_with_no_open_trade_raises_no_exit(self):
- frame = _frame([1], do_predict=2)
- with mock.patch(
- "ReforceXY.user_data.strategies.RLAgentStrategy.Trade.get_trades_proxy",
- return_value=[],
- ):
- result = self._strategy().populate_exit_trend(frame, {"pair": "BTC/USDT"})
- self.assertFalse(_raised(result["exit_long"])[0])
- self.assertFalse(_raised(result["exit_short"])[0])
-
class FeatureEngineeringTest(QaTestCase):
def _strategy(self):
finally:
reseed(previous)
- def test_the_restore_puts_the_process_globals_back(self):
+ def test_the_lifecycle_restores_globals_before_body_and_after_all_outcomes(self):
cache = _PRODUCTION.ReforceXY._action_masks_cache
- # Dirty every global the way a test that trains a model would.
- cache[("dirty", 0.5)] = None
- random.seed(1234)
- np.random.seed(1234)
- torch.manual_seed(1234)
- self.addCleanup(QaTestCase._restore_process_globals)
- QaTestCase._restore_process_globals()
+ def snapshot():
+ return (
+ dict(cache),
+ random.getstate(),
+ np.random.get_state(),
+ torch.random.get_rng_state().clone(),
+ )
- self.assertEqual(
- dict(_ACTION_MASKS_CACHE_AT_IMPORT),
- dict(cache),
- "_action_masks_cache was not restored",
- )
- self.assertEqual(_RANDOM_STATE_AT_IMPORT, random.getstate())
- self.assertEqual(
- _NUMPY_STATE_AT_IMPORT[1].tolist(),
- np.random.get_state()[1].tolist(),
- "the numpy bit generator was not rewound",
- )
- self.assertEqual(
- int(_NUMPY_STATE_AT_IMPORT[2]),
- int(np.random.get_state()[2]),
- "the numpy stream position advanced and was not restored",
- )
- if _TORCH_STATE_AT_IMPORT is not None:
- self.assertTrue(torch.equal(torch.random.get_rng_state(), _TORCH_STATE_AT_IMPORT))
+ entry = snapshot()
+
+ def restore_entry():
+ cache.clear()
+ cache.update(entry[0])
+ random.setstate(entry[1])
+ np.random.set_state(entry[2])
+ torch.random.set_rng_state(entry[3])
+
+ self.addCleanup(restore_entry)
+
+ def dirty():
+ cache[("lifecycle-probe", 0.5)] = None
+ random.seed(1234)
+ np.random.seed(1234)
+ torch.manual_seed(1234)
+
+ def assert_baseline(state):
+ self.assertEqual(state[0], dict(_ACTION_MASKS_CACHE_AT_IMPORT))
+ self.assertEqual(state[1], _RANDOM_STATE_AT_IMPORT)
+ self.assertEqual(state[2][0], _NUMPY_STATE_AT_IMPORT[0])
+ np.testing.assert_array_equal(state[2][1], _NUMPY_STATE_AT_IMPORT[1])
+ self.assertEqual(state[2][2:], _NUMPY_STATE_AT_IMPORT[2:])
+ if _TORCH_STATE_AT_IMPORT is not None:
+ self.assertTrue(torch.equal(state[3], _TORCH_STATE_AT_IMPORT))
+
+ class Probe(QaTestCase):
+ def __init__(self, outcome):
+ super().__init__()
+ self.outcome = outcome
+ self.observed = []
+
+ def setUp(self):
+ super().setUp()
+ self.observed.append(snapshot())
+ if self.outcome == "setup-error":
+ dirty()
+ raise RuntimeError("intentional setup-error")
+
+ def runTest(self):
+ self.observed.append(snapshot())
+ dirty()
+ if self.outcome == "body-failure":
+ self.fail("intentional body-failure")
+
+ def tearDown(self):
+ if self.outcome == "teardown-error":
+ dirty()
+ raise RuntimeError("intentional teardown-error")
+
+ for outcome in ("success", "body-failure", "setup-error", "teardown-error"):
+ with self.subTest(outcome=outcome):
+ dirty()
+ result = unittest.TestResult()
+ probe = Probe(outcome)
+ probe.run(result)
+ self.assertEqual(result.testsRun, 1)
+ self.assertEqual(len(probe.observed), 1 if outcome == "setup-error" else 2)
+ for state in probe.observed:
+ assert_baseline(state)
+ assert_baseline(snapshot())
+ self.assertEqual(len(result.failures), int(outcome == "body-failure"))
+ self.assertEqual(len(result.errors), int(outcome.endswith("error")))
+ for _, traceback in result.failures + result.errors:
+ self.assertIn(f"intentional {outcome}", traceback)
if __name__ == "__main__":
_LOG_2: Final[float] = math.log(2.0)
_DEPLOYMENT_COORDINATE_MARKER_KEY: Final[str] = "reforcexy_deployment_coordinates"
- _DEPLOYMENT_COORDINATE_GENERATION: Final[str] = "chronological-frozen-pipelines-v2"
+ _DEPLOYMENT_COORDINATE_GENERATION: Final[str] = "chronological-frozen-pipelines-pbrs-v3"
DEFAULT_BASE_FACTOR: Final[float] = 100.0
DEFAULT_DISCOUNT_GAMMA: Final[float] = 0.95
_BEST_PARAMS_LOCK_FILENAME: Final[str] = ".hyperopt-best-params.lock"
# Bump on objective changes that make persisted trials or best params incompatible.
_OPTUNA_OBJECTIVE_IDENTITY: Final[str] = (
- "terminal-liquidation-risk-normalized-trained-policy-v4"
+ "terminal-liquidation-risk-normalized-trained-policy-v5"
)
_PPO_N_STEPS: Final[tuple[int, ...]] = (512, 1024, 2048, 4096)
_PPO_N_STEPS_MIN: Final[int] = min(_PPO_N_STEPS)
@staticmethod
def _resolve_discount_gamma(model_params: Mapping[str, Any]) -> float:
- """Resolve discount after precedence, rejecting explicit null instead of defaulting."""
+ """Validate the winning Python/NumPy real scalar discount and normalize to float."""
gamma = model_params.get("gamma", ReforceXY.DEFAULT_DISCOUNT_GAMMA)
if gamma is None:
raise ValueError(
"Config [global]: effective model_training_parameters.gamma must not be null"
)
- return cast("float", gamma)
+ if (
+ isinstance(gamma, (bool, np.bool_))
+ or not isinstance(gamma, (int, float, np.integer, np.floating))
+ or not 0 <= gamma <= 1
+ ):
+ raise ValueError(
+ "Config [global]: effective discount gamma must be a finite real scalar in [0, 1]"
+ )
+ return float(gamma)
def set_train_and_eval_environments(
self,
cached = self.dd.meta_data_dictionary.get(pair, {})
metadata = cached.get(METADATA)
feature_pipeline = cached.get(FEATURE_PIPELINE)
+ prefix: Path | None = None
if model is None or metadata is None or feature_pipeline is None:
# The current kitchen points to the new window, not deployed files.
previous_dk = copy.copy(dk)
if metadata is None:
with Path(f"{prefix}_{METADATA}.json").open("r") as fp:
metadata = rapidjson.load(fp, number_mode=METADATA_NUMBER_MODE)
- if feature_pipeline is None:
- with Path(f"{prefix}_{FEATURE_PIPELINE}.pkl").open("rb") as fp:
- feature_pipeline = cloudpickle.load(fp)
- if model is None:
- model = self.MODELCLASS.load(Path(f"{prefix}_model"))
- self._restore_replay(model, metadata, previous_dk.data_path, pair)
if (
metadata.get(self._DEPLOYMENT_COORDINATE_MARKER_KEY)
!= self._DEPLOYMENT_COORDINATE_GENERATION
):
raise ValueError(
- "persisted deployment coordinate generation is missing or incompatible"
+ "persisted deployment coordinate/reward generation is missing or incompatible"
)
+ if feature_pipeline is None:
+ assert prefix is not None
+ with Path(f"{prefix}_{FEATURE_PIPELINE}.pkl").open("rb") as fp:
+ feature_pipeline = cloudpickle.load(fp)
+ if model is None:
+ assert prefix is not None
+ model = self.MODELCLASS.load(Path(f"{prefix}_model"))
if not isinstance(model, self.MODELCLASS):
raise ValueError("persisted policy type differs from the configured model")
+ ReforceXY._resolve_discount_gamma({"gamma": getattr(model, "gamma", None)})
for name, expected, actual in (
("features", dk.training_features_list, metadata["training_features_list"]),
("labels", dk.label_list, metadata["label_list"]),
):
if list(expected) != list(actual):
raise ValueError(f"persisted {name} differ in names or order")
+ if cached_model is None:
+ self._restore_replay(model, metadata, Path(previous["data_path"]), pair)
if cached_model is not None:
# SB3 archives preserve policy/optimizer state but exclude envs and loggers.
with BytesIO() as archive:
model = deployment_state[0] if deployment_state is not None else None
effective_params = dict(model_params)
if model is not None:
- learner_gamma = getattr(model, "gamma", None)
- if isinstance(learner_gamma, (int, float)) and np.isfinite(learner_gamma):
- effective_params["gamma"] = float(learner_gamma)
+ effective_params["gamma"] = getattr(model, "gamma", None)
effective_params["gamma"] = ReforceXY._resolve_discount_gamma(effective_params)
# Preserve raw prices and the resumed learner's discount in its environments.
try:
)
)
# === PBRS COMMON PARAMETERS ===
- self._potential_gamma = float(
- model_reward_parameters.get("potential_gamma", ReforceXY.DEFAULT_DISCOUNT_GAMMA)
+ self._potential_gamma = ReforceXY._resolve_discount_gamma(
+ {
+ "gamma": model_reward_parameters.get(
+ "potential_gamma", ReforceXY.DEFAULT_DISCOUNT_GAMMA
+ )
+ }
)
if np.isclose(self._potential_gamma, 0.0):
logger.warning(
computed_reward_shaping = self._last_reward_shaping
terminal_reward_shaping = -prev_potential
reward_shaping_delta = terminal_reward_shaping - computed_reward_shaping
- last_next_potential = self._last_next_potential
-
- if np.isclose(computed_reward_shaping, terminal_reward_shaping) and np.isclose(
- last_next_potential, 0.0
- ):
- self._last_potential = 0.0
- self._last_next_potential = 0.0
- return reward
-
self._last_potential = 0.0
self._last_next_potential = 0.0
self._last_reward_shaping = terminal_reward_shaping
{
"n_steps": int(optuna_params.get("n_steps")),
"batch_size": int(optuna_params.get("batch_size")),
- "gamma": float(optuna_params.get("gamma")),
+ "gamma": ReforceXY._resolve_discount_gamma(optuna_params),
"learning_rate": lr,
"ent_coef": float(optuna_params.get("ent_coef")),
"clip_range": cr,
model_params.update(
{
- "gamma": float(optuna_params.get("gamma")),
+ "gamma": ReforceXY._resolve_discount_gamma(optuna_params),
"batch_size": int(optuna_params.get("batch_size")),
"learning_rate": lr,
"buffer_size": int(optuna_params.get("buffer_size")),