]> Piment Noir Git Repositories - freqai-strategies.git/commitdiff
feat(quickadapter): add entry reversal toggle (#305)
authorJérôme Benoit <jerome.benoit@piment-noir.org>
Thu, 5 Nov 2026 00:29:11 +0000 (01:29 +0100)
committerGitHub <noreply@github.com>
Thu, 5 Nov 2026 00:29:11 +0000 (01:29 +0100)
* feat(quickadapter): add entry reversal toggle

Default the entry-only switch to true to preserve existing behavior.
Disabling it retains numeric settings, exit confirmation and other
entry guards.

* refactor(quickadapter): use section-level enabled

* chore(quickadapter): bump version to 3.13.2

quickadapter/.basedpyright/diagnostics.json
quickadapter/README.md
quickadapter/tests/test_strategy_sizing.py
quickadapter/tests/test_utils_config_resolution.py
quickadapter/user_data/config-template.json
quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py
quickadapter/user_data/strategies/QuickAdapterV3.py
quickadapter/user_data/strategies/Utils.py

index efa25c43181b9bac0e9533519e0ed7cec94d4d06..144f8a692dacfa7d0d76bb58414c3cde9570062e 100644 (file)
     },
     {
       "endCharacter": 38,
-      "endLine": 785,
+      "endLine": 786,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "\"to_numpy\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 30,
-      "startLine": 785
+      "startLine": 786
     },
     {
       "endCharacter": 44,
-      "endLine": 818,
+      "endLine": 819,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"-\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 38,
-      "startLine": 818
+      "startLine": 819
     },
     {
       "endCharacter": 38,
-      "endLine": 826,
+      "endLine": 827,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Object of type \"None\" is not subscriptable",
       "rule": "reportOptionalSubscript",
       "severity": "error",
       "startCharacter": 36,
-      "startLine": 826
+      "startLine": 827
     },
     {
       "endCharacter": 39,
-      "endLine": 827,
+      "endLine": 828,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Object of type \"None\" is not subscriptable",
       "rule": "reportOptionalSubscript",
       "severity": "error",
       "startCharacter": 37,
-      "startLine": 827
+      "startLine": 828
     },
     {
       "endCharacter": 38,
-      "endLine": 828,
+      "endLine": 829,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Object of type \"None\" is not subscriptable",
       "rule": "reportOptionalSubscript",
       "severity": "error",
       "startCharacter": 36,
-      "startLine": 828
+      "startLine": 829
     },
     {
       "endCharacter": 44,
-      "endLine": 851,
+      "endLine": 852,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"-\" not supported for types \"Series[Any] | None\" and \"Series[Any] | None\"\n  Operator \"-\" not supported for types \"Series[Any]\" and \"None\"\n  Operator \"-\" not supported for types \"None\" and \"Series[Any]\"\n  Operator \"-\" not supported for types \"None\" and \"None\"",
       "rule": "reportOperatorIssue",
       "severity": "error",
       "startCharacter": 29,
-      "startLine": 851
+      "startLine": 852
     },
     {
       "endCharacter": 66,
-      "endLine": 851,
+      "endLine": 852,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"s1\" of type \"Series[Any]\" in function \"non_zero_diff\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 61,
-      "startLine": 851
+      "startLine": 852
     },
     {
       "endCharacter": 72,
-      "endLine": 851,
+      "endLine": 852,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"s2\" of type \"Series[Any]\" in function \"non_zero_diff\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 68,
-      "startLine": 851
+      "startLine": 852
     },
     {
       "endCharacter": 56,
-      "endLine": 857,
+      "endLine": 858,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"p1\" of type \"T@get_distance\" in function \"get_distance\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 50,
-      "startLine": 857
+      "startLine": 858
     },
     {
       "endCharacter": 58,
-      "endLine": 858,
+      "endLine": 859,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"p1\" of type \"T@get_distance\" in function \"get_distance\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 52,
-      "startLine": 858
+      "startLine": 859
     },
     {
       "endCharacter": 57,
-      "endLine": 859,
+      "endLine": 860,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"p1\" of type \"T@get_distance\" in function \"get_distance\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 51,
-      "startLine": 859
+      "startLine": 860
     },
     {
       "endCharacter": 44,
-      "endLine": 862,
+      "endLine": 863,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"series\" of type \"Series[Any]\" in function \"zlema\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 38,
-      "startLine": 862
+      "startLine": 863
     },
     {
       "endCharacter": 44,
-      "endLine": 863,
+      "endLine": 864,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"series\" of type \"Series[Any]\" in function \"zlema\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 38,
-      "startLine": 863
+      "startLine": 864
     },
     {
       "endCharacter": 44,
-      "endLine": 864,
+      "endLine": 865,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"series\" of type \"Series[Any]\" in function \"zlema\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 38,
-      "startLine": 864
+      "startLine": 865
     },
     {
       "endCharacter": 61,
-      "endLine": 865,
+      "endLine": 866,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"p1\" of type \"T@get_distance\" in function \"get_distance\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 55,
-      "startLine": 865
+      "startLine": 866
     },
     {
       "endCharacter": 61,
-      "endLine": 866,
+      "endLine": 867,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"p1\" of type \"T@get_distance\" in function \"get_distance\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 55,
-      "startLine": 866
+      "startLine": 867
     },
     {
       "endCharacter": 61,
-      "endLine": 867,
+      "endLine": 868,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"p1\" of type \"T@get_distance\" in function \"get_distance\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 55,
-      "startLine": 867
+      "startLine": 868
     },
     {
       "endCharacter": 81,
-      "endLine": 875,
+      "endLine": 876,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any]\" cannot be assigned to parameter \"p2\" of type \"T@get_distance\" in function \"get_distance\"\n  \"Series[Any]\" is not assignable to \"float\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 58,
-      "startLine": 875
+      "startLine": 876
     },
     {
       "endCharacter": 67,
-      "endLine": 888,
+      "endLine": 889,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"p1\" of type \"T@get_distance\" in function \"get_distance\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 61,
-      "startLine": 888
+      "startLine": 889
     },
     {
       "endCharacter": 68,
-      "endLine": 889,
+      "endLine": 890,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"p1\" of type \"T@get_distance\" in function \"get_distance\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 62,
-      "startLine": 889
+      "startLine": 890
     },
     {
       "endCharacter": 67,
-      "endLine": 890,
+      "endLine": 891,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"p1\" of type \"T@get_distance\" in function \"get_distance\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 61,
-      "startLine": 890
+      "startLine": 891
     },
     {
       "endCharacter": 44,
-      "endLine": 891,
+      "endLine": 892,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"-\" not supported for types \"Series[Any] | None\" and \"Series[Any] | None\"\n  Operator \"-\" not supported for types \"Series[Any]\" and \"None\" when expected type is \"_SetItemValueNotDataFrame\"\n  Operator \"-\" not supported for types \"None\" and \"Series[Any]\" when expected type is \"_SetItemValueNotDataFrame\"\n  Operator \"-\" not supported for types \"None\" and \"None\" when expected type is \"_SetItemValueNotDataFrame\"",
       "rule": "reportOperatorIssue",
       "severity": "error",
       "startCharacter": 30,
-      "startLine": 891
+      "startLine": 892
     },
     {
       "endCharacter": 56,
-      "endLine": 892,
+      "endLine": 893,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "No overloads for \"__call__\" match the provided arguments",
       "rule": "reportCallIssue",
       "severity": "error",
       "startCharacter": 31,
-      "startLine": 892
+      "startLine": 893
     },
     {
       "endCharacter": 47,
-      "endLine": 892,
+      "endLine": 893,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"x1\" of type \"ArrayLike\" in function \"__call__\"\n  Type \"Series[Any] | None\" is not assignable to type \"ArrayLike\"\n    Type \"None\" is not assignable to type \"ArrayLike\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"_SupportsArray[dtype[Any]]\"\n        \"__array__\" is not present\n      \"None\" is incompatible with protocol \"_NestedSequence[_SupportsArray[dtype[Any]]]\"\n        \"__len__\" is not present\n  ...",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 42,
-      "startLine": 892
+      "startLine": 893
     },
     {
       "endCharacter": 55,
-      "endLine": 892,
+      "endLine": 893,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"x2\" of type \"ArrayLike\" in function \"__call__\"\n  Type \"Series[Any] | None\" is not assignable to type \"ArrayLike\"\n    Type \"None\" is not assignable to type \"ArrayLike\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"_SupportsArray[dtype[Any]]\"\n        \"__array__\" is not present\n      \"None\" is incompatible with protocol \"_NestedSequence[_SupportsArray[dtype[Any]]]\"\n        \"__len__\" is not present\n  ...",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 49,
-      "startLine": 892
+      "startLine": 893
     },
     {
       "endCharacter": 64,
-      "endLine": 893,
+      "endLine": 894,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "No overloads for \"__call__\" match the provided arguments",
       "rule": "reportCallIssue",
       "severity": "error",
       "startCharacter": 39,
-      "startLine": 893
+      "startLine": 894
     },
     {
       "endCharacter": 55,
-      "endLine": 893,
+      "endLine": 894,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"x1\" of type \"ArrayLike\" in function \"__call__\"\n  Type \"Series[Any] | None\" is not assignable to type \"ArrayLike\"\n    Type \"None\" is not assignable to type \"ArrayLike\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"_SupportsArray[dtype[Any]]\"\n        \"__array__\" is not present\n      \"None\" is incompatible with protocol \"_NestedSequence[_SupportsArray[dtype[Any]]]\"\n        \"__len__\" is not present\n  ...",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 50,
-      "startLine": 893
+      "startLine": 894
     },
     {
       "endCharacter": 63,
-      "endLine": 893,
+      "endLine": 894,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"x2\" of type \"ArrayLike\" in function \"__call__\"\n  Type \"Series[Any] | None\" is not assignable to type \"ArrayLike\"\n    Type \"None\" is not assignable to type \"ArrayLike\"\n      \"None\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"None\" is incompatible with protocol \"_SupportsArray[dtype[Any]]\"\n        \"__array__\" is not present\n      \"None\" is incompatible with protocol \"_NestedSequence[_SupportsArray[dtype[Any]]]\"\n        \"__len__\" is not present\n  ...",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 57,
-      "startLine": 893
-    },
-    {
-      "endCharacter": 55,
-      "endLine": 901,
-      "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
-      "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"p1\" of type \"T@get_distance\" in function \"get_distance\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
-      "rule": "reportArgumentType",
-      "severity": "error",
-      "startCharacter": 49,
-      "startLine": 901
+      "startLine": 894
     },
     {
       "endCharacter": 55,
       "startCharacter": 49,
       "startLine": 906
     },
+    {
+      "endCharacter": 55,
+      "endLine": 907,
+      "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
+      "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"p1\" of type \"T@get_distance\" in function \"get_distance\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
+      "rule": "reportArgumentType",
+      "severity": "error",
+      "startCharacter": 49,
+      "startLine": 907
+    },
     {
       "endCharacter": 50,
-      "endLine": 935,
+      "endLine": 936,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.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": 44,
-      "startLine": 935
+      "startLine": 936
     },
     {
       "endCharacter": 50,
-      "endLine": 935,
+      "endLine": 936,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.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": 44,
-      "startLine": 935
+      "startLine": 936
     },
     {
       "endCharacter": 29,
-      "endLine": 936,
+      "endLine": 937,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.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": 23,
-      "startLine": 936
+      "startLine": 937
     },
     {
       "endCharacter": 29,
-      "endLine": 936,
+      "endLine": 937,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.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": 23,
-      "startLine": 936
+      "startLine": 937
     },
     {
       "endCharacter": 60,
-      "endLine": 973,
+      "endLine": 974,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.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": 50,
-      "startLine": 973
+      "startLine": 974
     },
     {
       "endCharacter": 60,
-      "endLine": 973,
+      "endLine": 974,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.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": 50,
-      "startLine": 973
+      "startLine": 974
     },
     {
       "endCharacter": 35,
-      "endLine": 974,
+      "endLine": 975,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.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": 25,
-      "startLine": 974
+      "startLine": 975
     },
     {
       "endCharacter": 35,
-      "endLine": 974,
+      "endLine": 975,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.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": 25,
-      "startLine": 974
+      "startLine": 975
     },
     {
       "endCharacter": 41,
-      "endLine": 1199,
+      "endLine": 1200,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"<\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 12,
-      "startLine": 1199
+      "startLine": 1200
     },
     {
       "endCharacter": 41,
-      "endLine": 1209,
+      "endLine": 1210,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \">\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 12,
-      "startLine": 1209
+      "startLine": 1210
     },
     {
       "endCharacter": 66,
-      "endLine": 1222,
+      "endLine": 1223,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"timeframe\" of type \"str\" in function \"timeframe_to_prev_date\"\n  Type \"Any | None\" is not assignable to type \"str\"\n    \"None\" is not assignable to \"str\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 38,
-      "startLine": 1222
+      "startLine": 1223
     },
     {
       "endCharacter": 70,
-      "endLine": 1353,
+      "endLine": 1354,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Expected 1 more positional argument",
       "rule": "reportCallIssue",
       "severity": "error",
       "startCharacter": 48,
-      "startLine": 1353
+      "startLine": 1354
     },
     {
       "endCharacter": 74,
-      "endLine": 1417,
+      "endLine": 1418,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"int | None\" cannot be assigned to parameter \"trade_duration_candles\" of type \"int\" in function \"get_trade_natr\"\n  Type \"int | None\" is not assignable to type \"int\"\n    \"None\" is not assignable to \"int\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 52,
-      "startLine": 1417
+      "startLine": 1418
     },
     {
       "endCharacter": 74,
-      "endLine": 1444,
+      "endLine": 1445,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"int | None\" cannot be assigned to parameter \"trade_duration_candles\" of type \"int\" in function \"get_trade_natr\"\n  Type \"int | None\" is not assignable to type \"int\"\n    \"None\" is not assignable to \"int\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 52,
-      "startLine": 1444
+      "startLine": 1445
     },
     {
       "endCharacter": 96,
-      "endLine": 1496,
+      "endLine": 1497,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"timeframe\" of type \"str\" in function \"get_analyzed_dataframe\"\n  Type \"Any | None\" is not assignable to type \"str\"\n    \"None\" is not assignable to \"str\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 68,
-      "startLine": 1496
+      "startLine": 1497
     },
     {
       "endCharacter": 77,
-      "endLine": 1526,
+      "endLine": 1527,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"<=\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 57,
-      "startLine": 1526
+      "startLine": 1527
     },
     {
       "endCharacter": 9,
-      "endLine": 1531,
+      "endLine": 1532,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"+\" not supported for types \"float\" and \"float | None\"\n  Operator \"+\" not supported for types \"float\" and \"None\"",
       "rule": "reportOperatorIssue",
       "severity": "error",
       "startCharacter": 28,
-      "startLine": 1529
+      "startLine": 1530
     },
     {
       "endCharacter": 33,
-      "endLine": 1530,
+      "endLine": 1531,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"-\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 13,
-      "startLine": 1530
+      "startLine": 1531
     },
     {
       "endCharacter": 67,
-      "endLine": 1536,
+      "endLine": 1537,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.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": 47,
-      "startLine": 1536
+      "startLine": 1537
     },
     {
       "endCharacter": 67,
-      "endLine": 1536,
+      "endLine": 1537,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.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": 47,
-      "startLine": 1536
+      "startLine": 1537
     },
     {
       "endCharacter": 64,
-      "endLine": 1690,
+      "endLine": 1691,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "\"isoformat\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 55,
-      "startLine": 1690
+      "startLine": 1691
     },
     {
       "endCharacter": 37,
-      "endLine": 1741,
+      "endLine": 1742,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"<=\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 15,
-      "startLine": 1741
+      "startLine": 1742
     },
     {
       "endCharacter": 48,
-      "endLine": 1743,
+      "endLine": 1744,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"<=\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 15,
-      "startLine": 1743
+      "startLine": 1744
     },
     {
       "endCharacter": 96,
-      "endLine": 1923,
+      "endLine": 1924,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"timeframe\" of type \"str\" in function \"get_analyzed_dataframe\"\n  Type \"Any | None\" is not assignable to type \"str\"\n    \"None\" is not assignable to \"str\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 68,
-      "startLine": 1923
+      "startLine": 1924
     },
     {
       "endCharacter": 39,
-      "endLine": 2026,
+      "endLine": 2027,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"+\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 21,
-      "startLine": 2026
+      "startLine": 2027
     },
     {
       "endCharacter": 90,
-      "endLine": 2026,
+      "endLine": 2027,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"*\" not supported for types \"float\" and \"Any | None\"\n  Operator \"*\" not supported for types \"float\" and \"None\"",
       "rule": "reportOperatorIssue",
       "severity": "error",
       "startCharacter": 62,
-      "startLine": 2026
+      "startLine": 2027
     },
     {
       "endCharacter": 96,
-      "endLine": 2328,
+      "endLine": 2329,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"timeframe\" of type \"str\" in function \"get_analyzed_dataframe\"\n  Type \"Any | None\" is not assignable to type \"str\"\n    \"None\" is not assignable to \"str\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 68,
-      "startLine": 2328
+      "startLine": 2329
     },
     {
       "endCharacter": 85,
-      "endLine": 2353,
+      "endLine": 2354,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "\"isoformat\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 76,
-      "startLine": 2353
+      "startLine": 2354
     },
     {
       "endCharacter": 47,
-      "endLine": 2359,
+      "endLine": 2360,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \"<\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2359
+      "startLine": 2360
     },
     {
       "endCharacter": 69,
-      "endLine": 2366,
+      "endLine": 2367,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
-      "message": "Argument of type \"int | float\" cannot be assigned to parameter \"lookback_period_candles\" of type \"int\" in function \"reversal_confirmed\"\n  Type \"int | float\" is not assignable to type \"int\"\n    \"float\" is not assignable to \"int\"",
+      "message": "Argument of type \"bool | int | float\" cannot be assigned to parameter \"lookback_period_candles\" of type \"int\" in function \"reversal_confirmed\"\n  Type \"bool | int | float\" is not assignable to type \"int\"\n    \"float\" is not assignable to \"int\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2366
+      "startLine": 2367
     },
     {
       "endCharacter": 47,
-      "endLine": 2377,
+      "endLine": 2378,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Operator \">\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2377
+      "startLine": 2378
     },
     {
       "endCharacter": 69,
-      "endLine": 2384,
+      "endLine": 2385,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
-      "message": "Argument of type \"int | float\" cannot be assigned to parameter \"lookback_period_candles\" of type \"int\" in function \"reversal_confirmed\"\n  Type \"int | float\" is not assignable to type \"int\"\n    \"float\" is not assignable to \"int\"",
+      "message": "Argument of type \"bool | int | float\" cannot be assigned to parameter \"lookback_period_candles\" of type \"int\" in function \"reversal_confirmed\"\n  Type \"bool | int | float\" is not assignable to type \"int\"\n    \"float\" is not assignable to \"int\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2384
+      "startLine": 2385
     },
     {
       "endCharacter": 52,
-      "endLine": 2413,
+      "endLine": 2414,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"datetime | None\" cannot be assigned to parameter \"current_candle_date\" of type \"datetime\" in function \"_normalize_final_take_profit_state\"\n  Type \"datetime | None\" is not assignable to type \"datetime\"\n    \"None\" is not assignable to \"datetime\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 36,
-      "startLine": 2413
+      "startLine": 2414
     },
     {
       "endCharacter": 96,
-      "endLine": 2533,
+      "endLine": 2534,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"Any | None\" cannot be assigned to parameter \"timeframe\" of type \"str\" in function \"get_analyzed_dataframe\"\n  Type \"Any | None\" is not assignable to type \"str\"\n    \"None\" is not assignable to \"str\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 68,
-      "startLine": 2533
+      "startLine": 2534
     },
     {
       "endCharacter": 69,
-      "endLine": 2544,
+      "endLine": 2547,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
-      "message": "Argument of type \"int | float\" cannot be assigned to parameter \"lookback_period_candles\" of type \"int\" in function \"reversal_confirmed\"\n  Type \"int | float\" is not assignable to type \"int\"\n    \"float\" is not assignable to \"int\"",
+      "message": "Argument of type \"bool | int | float\" cannot be assigned to parameter \"lookback_period_candles\" of type \"int\" in function \"reversal_confirmed\"\n  Type \"bool | int | float\" is not assignable to type \"int\"\n    \"float\" is not assignable to \"int\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 2544
+      "startLine": 2547
     },
     {
       "endCharacter": 32,
-      "endLine": 2624,
+      "endLine": 2627,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"LocalTrade\" cannot be assigned to parameter \"trade\" of type \"Trade\" in function \"get_trade_annotation_line_start_date\"\n  \"LocalTrade\" is not assignable to \"Trade\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 2624
+      "startLine": 2627
     },
     {
       "endCharacter": 72,
-      "endLine": 2627,
+      "endLine": 2630,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"LocalTrade\" cannot be assigned to parameter \"trade\" of type \"Trade\" in function \"get_trade_exit_stage\"\n  \"LocalTrade\" is not assignable to \"Trade\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 67,
-      "startLine": 2627
+      "startLine": 2630
     },
     {
       "endCharacter": 36,
-      "endLine": 2634,
+      "endLine": 2637,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"LocalTrade\" cannot be assigned to parameter \"trade\" of type \"Trade\" in function \"get_take_profit_target\"\n  \"LocalTrade\" is not assignable to \"Trade\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 31,
-      "startLine": 2634
+      "startLine": 2637
     },
     {
       "endCharacter": 71,
-      "endLine": 2665,
+      "endLine": 2668,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"LocalTrade\" cannot be assigned to parameter \"trade\" of type \"Trade\" in function \"get_trade_entry_date\"\n  \"LocalTrade\" is not assignable to \"Trade\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 66,
-      "startLine": 2665
+      "startLine": 2668
     },
     {
       "endCharacter": 32,
-      "endLine": 2698,
+      "endLine": 2701,
       "file": "quickadapter/user_data/strategies/QuickAdapterV3.py",
       "message": "Argument of type \"LocalTrade\" cannot be assigned to parameter \"trade\" of type \"Trade\" in function \"get_take_profit_target\"\n  \"LocalTrade\" is not assignable to \"Trade\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 2698
+      "startLine": 2701
     },
     {
       "endCharacter": 35,
     },
     {
       "endCharacter": 98,
-      "endLine": 1736,
+      "endLine": 1739,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Type \"bool | bool_\" is not assignable to return type \"bool\"\n  Type \"bool | bool_\" is not assignable to type \"bool\"\n    \"numpy.bool[builtins.bool]\" is not assignable to \"bool\"",
       "rule": "reportReturnType",
       "severity": "error",
       "startCharacter": 15,
-      "startLine": 1736
+      "startLine": 1739
     },
     {
       "endCharacter": 33,
-      "endLine": 1770,
+      "endLine": 1773,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"ScalarOrNA | bool_ | Period | Interval[Any]\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"ScalarOrNA | bool_ | Period | Interval[Any]\" is not assignable to type \"ConvertibleToInt\"\n    Type \"NAType\" is not assignable to type \"ConvertibleToInt\"\n      \"NAType\" is not assignable to \"str\"\n      \"NAType\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"NAType\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"NAType\" is incompatible with protocol \"SupportsIndex\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 1770
+      "startLine": 1773
     },
     {
       "endCharacter": 33,
-      "endLine": 1770,
+      "endLine": 1773,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"ScalarOrNA | bool_ | Period | Interval[Any]\" cannot be assigned to parameter \"x\" of type \"ConvertibleToInt\" in function \"__new__\"\n  Type \"ScalarOrNA | bool_ | Period | Interval[Any]\" is not assignable to type \"ConvertibleToInt\"\n    Type \"NAType\" is not assignable to type \"ConvertibleToInt\"\n      \"NAType\" is not assignable to \"str\"\n      \"NAType\" is incompatible with protocol \"Buffer\"\n        \"__buffer__\" is not present\n      \"NAType\" is incompatible with protocol \"SupportsInt\"\n        \"__int__\" is not present\n      \"NAType\" is incompatible with protocol \"SupportsIndex\"\n  ...",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 1770
+      "startLine": 1773
     },
     {
       "endCharacter": 23,
-      "endLine": 1782,
+      "endLine": 1785,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Type \"float\" is not assignable to return type \"T@get_distance\"\n  Type \"float\" is not assignable to type \"T@get_distance\"",
       "rule": "reportReturnType",
       "severity": "error",
       "startCharacter": 11,
-      "startLine": 1782
+      "startLine": 1785
     },
     {
       "endCharacter": 83,
-      "endLine": 2635,
+      "endLine": 2638,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"str\" cannot be assigned to parameter \"key\" of type \"CombinedMetric\" in function \"__getitem__\"\n  Type \"str\" is not assignable to type \"CombinedMetric\"\n    \"str\" is not assignable to type \"Literal['amplitude']\"\n    \"str\" is not assignable to type \"Literal['amplitude_threshold_ratio']\"\n    \"str\" is not assignable to type \"Literal['volume_rate']\"\n    \"str\" is not assignable to type \"Literal['speed']\"\n    \"str\" is not assignable to type \"Literal['efficiency_ratio']\"\n    \"str\" is not assignable to type \"Literal['volume_weighted_efficiency_ratio']\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 58,
-      "startLine": 2635
+      "startLine": 2638
     },
     {
       "endCharacter": 38,
-      "endLine": 3525,
+      "endLine": 3528,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Cannot access attribute \"__func__\" for class \"FunctionType\"\n  Attribute \"__func__\" is unknown",
       "rule": "reportFunctionMemberAccess",
       "severity": "error",
       "startCharacter": 30,
-      "startLine": 3525
+      "startLine": 3528
     },
     {
       "endCharacter": 34,
-      "endLine": 3527,
+      "endLine": 3530,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Cannot access attribute \"__func__\" for class \"FunctionType\"\n  Attribute \"__func__\" is unknown",
       "rule": "reportFunctionMemberAccess",
       "severity": "error",
       "startCharacter": 26,
-      "startLine": 3527
+      "startLine": 3530
     },
     {
       "endCharacter": 55,
-      "endLine": 3757,
+      "endLine": 3760,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"rolling\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 48,
-      "startLine": 3757
+      "startLine": 3760
     },
     {
       "endCharacter": 38,
-      "endLine": 3782,
+      "endLine": 3785,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"rolling\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 31,
-      "startLine": 3782
+      "startLine": 3785
     },
     {
       "endCharacter": 55,
-      "endLine": 3808,
+      "endLine": 3811,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"rolling\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 48,
-      "startLine": 3808
+      "startLine": 3811
     },
     {
       "endCharacter": 56,
-      "endLine": 3809,
+      "endLine": 3812,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"rolling\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 49,
-      "startLine": 3809
+      "startLine": 3812
     },
     {
       "endCharacter": 33,
-      "endLine": 3881,
+      "endLine": 3884,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"Series[Any] | NDArray[floating[Any]]\" cannot be assigned to parameter \"series\" of type \"Series[Any]\" in function \"calculate_zero_lag\"\n  Type \"Series[Any] | NDArray[floating[Any]]\" is not assignable to type \"Series[Any]\"\n    \"ndarray[_AnyShape, dtype[floating[Any]]]\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 3881
+      "startLine": 3884
     },
     {
       "endCharacter": 69,
-      "endLine": 3881,
+      "endLine": 3884,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Expected 1 more positional argument",
       "rule": "reportCallIssue",
       "severity": "error",
       "startCharacter": 59,
-      "startLine": 3881
+      "startLine": 3884
     },
     {
       "endCharacter": 40,
-      "endLine": 3948,
+      "endLine": 3951,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"series\" of type \"Series[Any]\" in function \"calculate_zero_lag\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 35,
-      "startLine": 3948
+      "startLine": 3951
     },
     {
       "endCharacter": 38,
-      "endLine": 3949,
+      "endLine": 3952,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"series\" of type \"Series[Any]\" in function \"calculate_zero_lag\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 34,
-      "startLine": 3949
+      "startLine": 3952
     },
     {
       "endCharacter": 42,
-      "endLine": 3950,
+      "endLine": 3953,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"Series[Any] | None\" cannot be assigned to parameter \"series\" of type \"Series[Any]\" in function \"calculate_zero_lag\"\n  Type \"Series[Any] | None\" is not assignable to type \"Series[Any]\"\n    \"None\" is not assignable to \"Series[Any]\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 36,
-      "startLine": 3950
+      "startLine": 3953
     },
     {
       "endCharacter": 45,
-      "endLine": 3952,
+      "endLine": 3955,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"index\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 40,
-      "startLine": 3952
+      "startLine": 3955
     },
     {
       "endCharacter": 33,
-      "endLine": 3954,
+      "endLine": 3957,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"iloc\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 29,
-      "startLine": 3954
+      "startLine": 3957
     },
     {
       "endCharacter": 31,
-      "endLine": 3955,
+      "endLine": 3958,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"iloc\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 3955
+      "startLine": 3958
     },
     {
       "endCharacter": 48,
-      "endLine": 3960,
+      "endLine": 3963,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"index\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 43,
-      "startLine": 3960
+      "startLine": 3963
     },
     {
       "endCharacter": 40,
-      "endLine": 3961,
+      "endLine": 3964,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"iloc\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 36,
-      "startLine": 3961
+      "startLine": 3964
     },
     {
       "endCharacter": 59,
-      "endLine": 3963,
+      "endLine": 3966,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Cannot access attribute \"iloc\" for class \"NDArray[Any]\"\n  Attribute \"iloc\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 55,
-      "startLine": 3963
+      "startLine": 3966
     },
     {
       "endCharacter": 34,
-      "endLine": 3965,
+      "endLine": 3968,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Cannot access attribute \"iloc\" for class \"NDArray[Any]\"\n  Attribute \"iloc\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 30,
-      "startLine": 3965
+      "startLine": 3968
     },
     {
       "endCharacter": 51,
-      "endLine": 3965,
+      "endLine": 3968,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"iloc\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 47,
-      "startLine": 3965
+      "startLine": 3968
     },
     {
       "endCharacter": 72,
-      "endLine": 3965,
+      "endLine": 3968,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Cannot access attribute \"iloc\" for class \"NDArray[Any]\"\n  Attribute \"iloc\" is unknown",
       "rule": "reportAttributeAccessIssue",
       "severity": "error",
       "startCharacter": 68,
-      "startLine": 3965
+      "startLine": 3968
     },
     {
       "endCharacter": 40,
-      "endLine": 4032,
+      "endLine": 4035,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Type \"(Series[Any] | NDArray[floating[Any]], int) -> (Series[Any] | NDArray[floating[Any]])\" is not assignable to declared type \"(series: Unknown, timeperiod: Unknown) -> Series[Any]\"\n  Type \"(Series[Any] | NDArray[floating[Any]], int) -> (Series[Any] | NDArray[floating[Any]])\" is not assignable to type \"(series: Unknown, timeperiod: Unknown) -> Series[Any]\"\n    Missing keyword parameter \"series\"\n    Missing keyword parameter \"timeperiod\"\n      Position-only parameter mismatch; parameter \"series\" is not position-only\n      Position-only parameter mismatch; parameter \"timeperiod\" is not position-only\n      Position-only parameter mismatch; expected 2 but received 0\n      Function return type \"Series[Any] | NDArray[floating[Any]]\" is incompatible with type \"Series[Any]\"\n        Type \"Series[Any] | NDArray[floating[Any]]\" is not assignable to type \"Series[Any]\"\n  ...",
       "rule": "reportAssignmentType",
       "severity": "error",
       "startCharacter": 20,
-      "startLine": 4032
+      "startLine": 4035
     },
     {
       "endCharacter": 33,
-      "endLine": 4034,
+      "endLine": 4037,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Type \"(Series[Any] | NDArray[floating[Any]], int) -> (Series[Any] | NDArray[floating[Any]])\" is not assignable to declared type \"(series: Unknown, timeperiod: Unknown) -> Series[Any]\"\n  Type \"(Series[Any] | NDArray[floating[Any]], int) -> (Series[Any] | NDArray[floating[Any]])\" is not assignable to type \"(series: Unknown, timeperiod: Unknown) -> Series[Any]\"\n    Missing keyword parameter \"series\"\n    Missing keyword parameter \"timeperiod\"\n      Position-only parameter mismatch; parameter \"series\" is not position-only\n      Position-only parameter mismatch; parameter \"timeperiod\" is not position-only\n      Position-only parameter mismatch; expected 2 but received 0\n      Function return type \"Series[Any] | NDArray[floating[Any]]\" is incompatible with type \"Series[Any]\"\n        Type \"Series[Any] | NDArray[floating[Any]]\" is not assignable to type \"Series[Any]\"\n  ...",
       "rule": "reportAssignmentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 4034
+      "startLine": 4037
     },
     {
       "endCharacter": 35,
-      "endLine": 4080,
+      "endLine": 4083,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"to_numpy\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 4080
+      "startLine": 4083
     },
     {
       "endCharacter": 33,
-      "endLine": 4081,
+      "endLine": 4084,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"to_numpy\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 25,
-      "startLine": 4081
+      "startLine": 4084
     },
     {
       "endCharacter": 37,
-      "endLine": 4198,
+      "endLine": 4201,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"to_numpy\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 29,
-      "startLine": 4198
+      "startLine": 4201
     },
     {
       "endCharacter": 35,
-      "endLine": 4199,
+      "endLine": 4202,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"to_numpy\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 4199
+      "startLine": 4202
     },
     {
       "endCharacter": 33,
-      "endLine": 4200,
+      "endLine": 4203,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"to_numpy\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 25,
-      "startLine": 4200
+      "startLine": 4203
     },
     {
       "endCharacter": 39,
-      "endLine": 4220,
+      "endLine": 4223,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"to_numpy\" is not a known attribute of \"None\"",
       "rule": "reportOptionalMemberAccess",
       "severity": "error",
       "startCharacter": 31,
-      "startLine": 4220
+      "startLine": 4223
     },
     {
       "endCharacter": 92,
-      "endLine": 4579,
+      "endLine": 4582,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Type \"bool_ | bool\" is not assignable to return type \"bool\"\n  Type \"bool_ | bool\" is not assignable to type \"bool\"\n    \"numpy.bool[builtins.bool]\" is not assignable to \"bool\"",
       "rule": "reportReturnType",
       "severity": "error",
       "startCharacter": 15,
-      "startLine": 4579
+      "startLine": 4582
     },
     {
       "endCharacter": 85,
-      "endLine": 4980,
+      "endLine": 4983,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"XGBoostPruningCallback\" cannot be assigned to parameter \"object\" of type \"RegressorCallback\" in function \"append\"\n  Type \"XGBoostPruningCallback\" is not assignable to type \"RegressorCallback\"\n    Type \"XGBoostPruningCallback\" is not assignable to type \"(...) -> Any\"\n    \"XGBoostPruningCallback\" is not assignable to \"TrainingCallback\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 16,
-      "startLine": 4980
+      "startLine": 4983
     },
     {
       "endCharacter": 29,
-      "endLine": 5023,
+      "endLine": 5026,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"list[tuple[DataFrame, DataFrame]] | None\" cannot be assigned to parameter \"eval_set\" of type \"List[_LGBM_ScikitValidSet] | None\" in function \"fit\"\n  Type \"list[tuple[DataFrame, DataFrame]] | None\" is not assignable to type \"List[_LGBM_ScikitValidSet] | None\"\n    Type \"list[tuple[DataFrame, DataFrame]]\" is not assignable to type \"List[_LGBM_ScikitValidSet] | None\"\n      \"list[tuple[DataFrame, DataFrame]]\" is not assignable to \"List[_LGBM_ScikitValidSet]\"\n        Type parameter \"_T@list\" is invariant, but \"tuple[DataFrame, DataFrame]\" is not the same as \"_LGBM_ScikitValidSet\"\n        Consider switching from \"list\" to \"Sequence\" which is covariant\n      \"list[tuple[DataFrame, DataFrame]]\" is not assignable to \"None\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 21,
-      "startLine": 5023
+      "startLine": 5026
     },
     {
       "endCharacter": 43,
-      "endLine": 5024,
+      "endLine": 5027,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"list[NDArray[floating[Any]]] | None\" cannot be assigned to parameter \"eval_sample_weight\" of type \"List[_LGBM_WeightType] | None\" in function \"fit\"\n  Type \"list[NDArray[floating[Any]]] | None\" is not assignable to type \"List[_LGBM_WeightType] | None\"\n    Type \"list[NDArray[floating[Any]]]\" is not assignable to type \"List[_LGBM_WeightType] | None\"\n      \"list[NDArray[floating[Any]]]\" is not assignable to \"List[_LGBM_WeightType]\"\n        Type parameter \"_T@list\" is invariant, but \"NDArray[floating[Any]]\" is not the same as \"_LGBM_WeightType\"\n        Consider switching from \"list\" to \"Sequence\" which is covariant\n      \"list[NDArray[floating[Any]]]\" is not assignable to \"None\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 31,
-      "startLine": 5024
+      "startLine": 5027
     },
     {
       "endCharacter": 62,
-      "endLine": 5027,
+      "endLine": 5030,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"list[RegressorCallback] | None\" cannot be assigned to parameter \"callbacks\" of type \"List[(...) -> Unknown] | None\" in function \"fit\"\n  Type \"list[RegressorCallback] | None\" is not assignable to type \"List[(...) -> Unknown] | None\"\n    Type \"list[RegressorCallback]\" is not assignable to type \"List[(...) -> Unknown] | None\"\n      \"list[RegressorCallback]\" is not assignable to \"List[(...) -> Unknown]\"\n        Type parameter \"_T@list\" is invariant, but \"RegressorCallback\" is not the same as \"(...) -> Unknown\"\n        Consider switching from \"list\" to \"Sequence\" which is covariant\n      \"list[RegressorCallback]\" is not assignable to \"None\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 22,
-      "startLine": 5027
+      "startLine": 5030
     },
     {
       "endCharacter": 35,
-      "endLine": 5049,
+      "endLine": 5052,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Object of type \"None\" is not subscriptable",
       "rule": "reportOptionalSubscript",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 5049
+      "startLine": 5052
     },
     {
       "endCharacter": 35,
-      "endLine": 5095,
+      "endLine": 5098,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Object of type \"None\" is not subscriptable",
       "rule": "reportOptionalSubscript",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 5095
+      "startLine": 5098
     },
     {
       "endCharacter": 49,
-      "endLine": 5165,
+      "endLine": 5168,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Argument of type \"CatBoostPruningCallback\" cannot be assigned to parameter \"object\" of type \"RegressorCallback\" in function \"append\"\n  Type \"CatBoostPruningCallback\" is not assignable to type \"RegressorCallback\"\n    Type \"CatBoostPruningCallback\" is not assignable to type \"(...) -> Any\"\n    \"CatBoostPruningCallback\" is not assignable to \"TrainingCallback\"",
       "rule": "reportArgumentType",
       "severity": "error",
       "startCharacter": 33,
-      "startLine": 5165
+      "startLine": 5168
     },
     {
       "endCharacter": 75,
-      "endLine": 5408,
+      "endLine": 5411,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Operator \"<=\" not supported for \"None\"",
       "rule": "reportOptionalOperand",
       "severity": "error",
       "startCharacter": 54,
-      "startLine": 5408
+      "startLine": 5411
     },
     {
       "endCharacter": 23,
-      "endLine": 5571,
+      "endLine": 5574,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"best_params\" is possibly unbound",
       "rule": "reportPossiblyUnboundVariable",
       "severity": "error",
       "startCharacter": 12,
-      "startLine": 5571
+      "startLine": 5574
     },
     {
       "endCharacter": 38,
-      "endLine": 5578,
+      "endLine": 5581,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"best_params\" is possibly unbound",
       "rule": "reportPossiblyUnboundVariable",
       "severity": "error",
       "startCharacter": 27,
-      "startLine": 5578
+      "startLine": 5581
     },
     {
       "endCharacter": 22,
-      "endLine": 5590,
+      "endLine": 5593,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "\"best_params\" is possibly unbound",
       "rule": "reportPossiblyUnboundVariable",
       "severity": "error",
       "startCharacter": 11,
-      "startLine": 5590
+      "startLine": 5593
     },
     {
       "endCharacter": 22,
-      "endLine": 5748,
+      "endLine": 5751,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Declaration \"default_ranges\" is obscured by a declaration of the same name",
       "rule": "reportRedeclaration",
       "severity": "error",
       "startCharacter": 8,
-      "startLine": 5748
+      "startLine": 5751
     },
     {
       "endCharacter": 14,
-      "endLine": 5784,
+      "endLine": 5787,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Declaration \"params\" is obscured by a declaration of the same name",
       "rule": "reportRedeclaration",
       "severity": "error",
       "startCharacter": 8,
-      "startLine": 5784
+      "startLine": 5787
     },
     {
       "endCharacter": 22,
-      "endLine": 5868,
+      "endLine": 5871,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Declaration \"default_ranges\" is obscured by a declaration of the same name",
       "rule": "reportRedeclaration",
       "severity": "error",
       "startCharacter": 8,
-      "startLine": 5868
+      "startLine": 5871
     },
     {
       "endCharacter": 14,
-      "endLine": 5902,
+      "endLine": 5905,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Declaration \"params\" is obscured by a declaration of the same name",
       "rule": "reportRedeclaration",
       "severity": "error",
       "startCharacter": 8,
-      "startLine": 5902
+      "startLine": 5905
     },
     {
       "endCharacter": 22,
-      "endLine": 5973,
+      "endLine": 5976,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Declaration \"default_ranges\" is obscured by a declaration of the same name",
       "rule": "reportRedeclaration",
       "severity": "error",
       "startCharacter": 8,
-      "startLine": 5973
+      "startLine": 5976
     },
     {
       "endCharacter": 22,
-      "endLine": 6074,
+      "endLine": 6077,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Declaration \"default_ranges\" is obscured by a declaration of the same name",
       "rule": "reportRedeclaration",
       "severity": "error",
       "startCharacter": 8,
-      "startLine": 6074
+      "startLine": 6077
     },
     {
       "endCharacter": 26,
-      "endLine": 6157,
+      "endLine": 6160,
       "file": "quickadapter/user_data/strategies/Utils.py",
       "message": "Declaration \"default_ranges\" is obscured by a declaration of the same name",
       "rule": "reportRedeclaration",
       "severity": "error",
       "startCharacter": 12,
-      "startLine": 6157
+      "startLine": 6160
     }
   ],
   "filesAnalyzed": 6,
index 05e7cedc276b4c4e923d95c2be14c0077d0f6621..d031bd17e88784f9be291c6a100dc538d6be2bff 100644 (file)
@@ -47,12 +47,13 @@ and installed dependency versions when comparing runs.
    `&s-extrema > maxima_threshold`, with the same validity gates. Equality does
    not trigger an entry. Adaptive thresholds need the real-prediction warmup
    described below.
-3. Entry confirmation also checks the current order price for the configured
-   volatility-adjusted reversal, available history, global capacity and per-side
-   capacity. A prediction signal alone does not guarantee a trade. Spot rejects
-   shorts; margin/futures can allow them. With both sides allowed, an odd finite
-   global capacity is rounded up before halving for each side; the global limit
-   still applies. `max_open_trades=-1` means unlimited capacity.
+3. Entry confirmation checks available data, global capacity and per-side capacity.
+   By default it also requires the configured volatility-adjusted price reversal
+   and confirming history; see [Reversal confirmation](#reversal-confirmation).
+   A prediction signal alone does not guarantee a trade. Spot rejects shorts;
+   margin/futures can allow them. With both sides allowed, an odd finite global
+   capacity is rounded up before halving for each side; the global limit still
+   applies. `max_open_trades=-1` means unlimited capacity.
 4. Open trades use the custom volatility-based stoploss, which never loosens,
    including after partial exits. The strategy stoploss is -2.5%; leverage,
    execution and exchange conditions affect the actual outcome.
@@ -327,12 +328,13 @@ The effective leverage is clamped to `[1.0, max_leverage]`, including proposal f
 
 ### Reversal confirmation
 
-| Path                                               | Runtime fallback | Type / Range | Description                                                                                                                                                |
-| -------------------------------------------------- | ---------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| reversal_confirmation.lookback_period_candles      | 0                | int >= 0     | Prior confirming candles; 0 = none. With confirmation enabled, unmeasurable history rejects entries, while a valid current exit may still reduce exposure. |
-| reversal_confirmation.decay_fraction               | 0.5              | float (0,1]  | Geometric per-candle volatility adjusted reversal threshold relaxation factor.                                                                             |
-| reversal_confirmation.min_natr_multiplier_fraction | 0.0095           | float [0,1]  | Lower bound fraction (< upper bound) for volatility adjusted reversal threshold.                                                                           |
-| reversal_confirmation.max_natr_multiplier_fraction | 0.0125           | float [0,1]  | Upper bound fraction (> lower bound) for volatility adjusted reversal threshold.                                                                           |
+| Path                                               | Runtime fallback | Type / Range | Description                                                                                                                                                                                           |
+| -------------------------------------------------- | ---------------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| reversal_confirmation.enabled                      | true             | bool         | Require price/history reversal for entries. `false` bypasses only this filter; exits and other entry guards remain active. Non-boolean values warn and use `true`. Numeric settings remain validated. |
+| reversal_confirmation.lookback_period_candles      | 0                | int >= 0     | Prior confirming candles; 0 checks only the current price. With the entry filter enabled, unmeasurable required history rejects entries. Exits may retain valid current-price confirmation.           |
+| reversal_confirmation.decay_fraction               | 0.5              | float (0,1]  | Geometric per-candle volatility adjusted reversal threshold relaxation factor.                                                                                                                        |
+| reversal_confirmation.min_natr_multiplier_fraction | 0.0095           | float [0,1]  | Lower bound fraction (< upper bound) for volatility adjusted reversal threshold.                                                                                                                      |
+| reversal_confirmation.max_natr_multiplier_fraction | 0.0125           | float [0,1]  | Upper bound fraction (> lower bound) for volatility adjusted reversal threshold.                                                                                                                      |
 
 ### Regressor model
 
index 1aa9129a3aea91f433a66018c278189ae46f3928..c232a2a8e35705a10f4a7c119155e129d95b0abc 100644 (file)
@@ -195,6 +195,7 @@ class RuntimeSizingTest(QaTestCase):
             directory,
             runmode=RunMode.BACKTEST,
             trading_mode="futures",
+            max_open_trades=4,
             exit_pricing={
                 "trade_natr_method": "quantile_interpolation",
                 "final_take_profit_retracement_fraction": 0.25,
@@ -282,6 +283,64 @@ class RuntimeSizingTest(QaTestCase):
     def exit(self, position, rate=100.0):
         return self.model.custom_exit(PAIR, position, self.now, rate, 0.0)
 
+    def entry(self, side="long", rate=100.0, open_trades=()):
+        with (
+            mock.patch.object(Trade, "get_open_trade_count", return_value=len(open_trades)),
+            mock.patch.object(Trade, "get_open_trades", return_value=open_trades),
+        ):
+            return self.model.confirm_trade_entry(
+                PAIR, "limit", 1.0, rate, "GTC", self.now, None, side
+            )
+
+    def test_entry_switch_only_bypasses_the_reversal_filter(self):
+        for side, passing_rate in (("long", 120.0), ("short", 80.0)):
+            with self.subTest(side=side):
+                self.assertFalse(self.entry(side))
+                self.assertTrue(self.entry(side, passing_rate))
+        for lookback in (0, len(self.frame)):
+            self.model.reversal_confirmation["lookback_period_candles"] = lookback
+            for enabled in (True, False):
+                self.model.reversal_confirmation["enabled"] = enabled
+                for side, passing_rate in (("long", 120.0), ("short", 80.0)):
+                    with self.subTest(lookback=lookback, enabled=enabled, side=side):
+                        self.assertIs(self.entry(side), not enabled)
+                        self.assertIs(self.entry(side, passing_rate), not enabled or lookback == 0)
+
+    def test_disabled_reversal_preserves_entry_rate_and_data_guards(self):
+        self.model.reversal_confirmation["enabled"] = False
+        for side in ("long", "short"):
+            self.assertTrue(self.entry(side, np.float64(100.0)))
+            for rate in (np.nan, np.inf, -np.inf, "100", None, True):
+                with self.subTest(side=side, rate=rate):
+                    self.assertFalse(self.entry(side, rate))
+        self.frame = self.frame.iloc[:0]
+        for side in ("long", "short"):
+            with self.subTest(side=side):
+                self.assertFalse(self.entry(side))
+
+    def test_disabled_reversal_preserves_side_authorization(self):
+        self.model.reversal_confirmation["enabled"] = False
+        self.assertFalse(self.entry("sideways"))
+        self.model.config["trading_mode"] = "spot"
+        self.assertFalse(self.entry("short"))
+        self.assertTrue(self.entry("long"))
+
+    def test_disabled_reversal_preserves_global_and_per_side_capacity(self):
+        self.model.reversal_confirmation["enabled"] = False
+        full = [self.position(short) for short in (False, True, False, True)]
+        for short, side in ((False, "long"), (True, "short")):
+            with self.subTest(side=side):
+                self.assertTrue(self.entry(side, open_trades=[self.position(short)]))
+                self.assertFalse(self.entry(side, open_trades=full))
+                self.assertFalse(
+                    self.entry(side, open_trades=[self.position(short), self.position(short)])
+                )
+                self.assertTrue(
+                    self.entry(
+                        side, open_trades=[self.position(not short), self.position(not short)]
+                    )
+                )
+
     def test_stoploss_distance_uses_current_not_entry_price(self):
         # Entry NATR 4 has mean rank 0.25 in [4, 8], giving interpolated NATR 7.
         # One candle has elapsed since entry; the price has moved from 100 to 120.
@@ -697,20 +756,22 @@ class RuntimeSizingTest(QaTestCase):
             (False, 0.5, 0.6, 80.0, "maxima_detected_long"),
             (True, -0.5, -0.6, 120.0, "minima_detected_short"),
         ):
-            with self.subTest(short=short):
-                position = self.position(short)
-                self.custom_data(position)
-                self.frame[EXTREMA_COLUMN] = boundary
-                self.assertIsNone(self.exit(position, rate))
-                self.frame[EXTREMA_COLUMN] = score
-                self.assertIsNone(self.exit(position, 100.0))
-                for prediction, inlier in ((0, 1), (1, 0)):
-                    self.frame["do_predict"] = prediction
-                    self.frame["DI_catch"] = inlier
+            for enabled in (True, False):
+                self.model.reversal_confirmation["enabled"] = enabled
+                with self.subTest(short=short, enabled=enabled):
+                    position = self.position(short)
+                    self.custom_data(position)
+                    self.frame[EXTREMA_COLUMN] = boundary
                     self.assertIsNone(self.exit(position, rate))
-                self.frame["do_predict"] = 1
-                self.frame["DI_catch"] = 1
-                self.assertEqual(self.exit(position, rate), tag)
+                    self.frame[EXTREMA_COLUMN] = score
+                    self.assertIsNone(self.exit(position, 100.0))
+                    for prediction, inlier in ((0, 1), (1, 0)):
+                        self.frame["do_predict"] = prediction
+                        self.frame["DI_catch"] = inlier
+                        self.assertIsNone(self.exit(position, rate))
+                    self.frame["do_predict"] = 1
+                    self.frame["DI_catch"] = 1
+                    self.assertEqual(self.exit(position, rate), tag)
 
     def test_final_exit_guards_preserve_unarmed_state(self):
         original = self.frame.copy()
index 3addb11daf71fd4594fa5b5e476be0e04c8dc534..1cf9dfb21d5eb3984fbf6b340fc092e6c109320e 100644 (file)
@@ -32,6 +32,7 @@ CANONICAL_PROTECTIONS: dict[str, Any] = {
     "stoploss": {"enabled": True},
 }
 CANONICAL_REVERSAL: dict[str, Any] = {
+    "enabled": True,
     "lookback_period_candles": 0,
     "decay_fraction": 0.5,
     "min_natr_multiplier_fraction": 0.0095,
@@ -418,6 +419,43 @@ class UtilsConfigResolutionTest(QaTestCase):
             ["Invalid reversal_confirmation value 'x': must be a mapping, using defaults"], sink
         )
 
+    def test_reversal_entry_switch_requires_a_boolean(self) -> None:
+        for enabled in (True, False):
+            with self.subTest(enabled=enabled):
+                with recorded_warnings() as (logger, sink):
+                    resolved = get_reversal_confirmation_config({"enabled": enabled}, logger)
+                self.assertIs(resolved["enabled"], enabled)
+                self.assertEqual([], sink)
+
+        for rejected in (0, 1, "false", None, np.bool_(False)):
+            with self.subTest(rejected=rejected):
+                with recorded_warnings() as (logger, sink):
+                    resolved = get_reversal_confirmation_config({"enabled": rejected}, logger)
+                self.assertIs(resolved["enabled"], True)
+                self.assertTrue(any("reversal_confirmation" in message for message in sink))
+
+    def test_disabled_entry_reversal_still_normalizes_numeric_constraints(self) -> None:
+        with recorded_warnings() as (logger, _):
+            resolved = get_reversal_confirmation_config(
+                {
+                    "enabled": False,
+                    "lookback_period_candles": -1,
+                    "decay_fraction": 0,
+                    "min_natr_multiplier_fraction": np.nan,
+                    "max_natr_multiplier_fraction": 2,
+                },
+                logger,
+            )
+        self.assertIs(resolved["enabled"], False)
+        self.assertGreaterEqual(resolved["lookback_period_candles"], 0)
+        self.assertGreater(resolved["decay_fraction"], 0)
+        self.assertLessEqual(resolved["decay_fraction"], 1)
+        self.assertGreaterEqual(resolved["min_natr_multiplier_fraction"], 0)
+        self.assertLess(
+            resolved["min_natr_multiplier_fraction"], resolved["max_natr_multiplier_fraction"]
+        )
+        self.assertLessEqual(resolved["max_natr_multiplier_fraction"], 1)
+
     def test_reversal_confirmation_scalar_fields_fall_back_with_their_constraints(self) -> None:
         with recorded_warnings() as (logger, sink):
             resolved = get_reversal_confirmation_config(
index def77314a59af362869f82c13186661c70ded684..e8d8b5680b3cb8adadf2f2c43f1c975edc22e9e6 100644 (file)
@@ -39,6 +39,7 @@
     "price_last_balance": 0.0
   },
   "reversal_confirmation": {
+    "enabled": true,
     "min_natr_multiplier_fraction": 0.0095,
     "max_natr_multiplier_fraction": 0.0125
   },
index 29389d417596a500c4da6ed32e9cf02795296297..e1eded5e629b8cfb6d13ee66c878e28ee82cbc04 100644 (file)
@@ -504,7 +504,7 @@ class QuickAdapterRegressorV3(BaseRegressionModel):
     https://github.com/sponsors/robcaulk
     """
 
-    version = "3.13.1"
+    version = "3.13.2"
 
     _CALIBRATION_START_KEY: Final[str] = "quickadapter_calibration_start"
     _DEPLOYMENT_COORDINATE_MARKER_KEY: Final[str] = "quickadapter_deployment_coordinates"
index 348d068aba098f4ae0077d267a22936ed740cfef..8989f0148648fa86cf0b2dfb32c3731d44101c0b 100644 (file)
@@ -221,7 +221,7 @@ class QuickAdapterV3(IStrategy):
     _ANNOTATION_LINE_OFFSET_CANDLES: Final[int] = 10
 
     def version(self) -> str:
-        return "3.13.1"
+        return "3.13.2"
 
     timeframe = "5m"
     timeframe_minutes = timeframe_to_minutes(timeframe)
@@ -487,7 +487,7 @@ class QuickAdapterV3(IStrategy):
         return exit_stage in QuickAdapterV3.partial_exit_stages()
 
     @cached_property
-    def reversal_confirmation(self) -> dict[str, int | float]:
+    def reversal_confirmation(self) -> dict[str, bool | int | float]:
         return get_reversal_confirmation_config(self.config.get("reversal_confirmation"), logger)
 
     @cached_property
@@ -664,6 +664,7 @@ class QuickAdapterV3(IStrategy):
                 )
 
         logger.info("Reversal Confirmation:")
+        logger.info(f"  enabled: {reversal_confirmation['enabled']}")
         logger.info(
             f"  lookback_period_candles: {reversal_confirmation['lookback_period_candles']}"
         )
@@ -2535,6 +2536,8 @@ class QuickAdapterV3(IStrategy):
         if df.empty:
             logger.info(f"[{pair}] Denied {side} {QuickAdapterV3._ORDER_ENTRY}: dataframe is empty")
             return False
+        if not self.reversal_confirmation["enabled"]:
+            return is_finite_number(rate)
         return bool(
             self.reversal_confirmed(
                 df,
index ec3934382e62a93a939f70b0b4b65706accf05a0..3cd60a2b61879d088be1b4ef25133299ac607d8d 100644 (file)
@@ -1665,6 +1665,7 @@ def normalize_fit_live_predictions_config(config: dict[str, Any], logger: Logger
 
 
 DEFAULTS_REVERSAL_CONFIRMATION: Final[dict[str, Any]] = {
+    "enabled": True,
     "lookback_period_candles": 0,
     "decay_fraction": 0.5,
     "min_natr_multiplier_fraction": 0.0095,
@@ -1675,6 +1676,7 @@ DEFAULTS_REVERSAL_CONFIRMATION: Final[dict[str, Any]] = {
 # cross-field ordering and per-component fallback, which ``_validate_params``
 # cannot express.
 _REVERSAL_CONFIRMATION_SCALAR_SPECS: Final[dict[str, _ParamSpec]] = {
+    "enabled": _ParamSpec(_BoolValidator()),
     "lookback_period_candles": _ParamSpec(
         _NumericValidator(min_value=0, require_int=True), output_type=int
     ),
@@ -1685,7 +1687,7 @@ _REVERSAL_CONFIRMATION_SCALAR_SPECS: Final[dict[str, _ParamSpec]] = {
 }
 
 
-def get_reversal_confirmation_config(config: Any, logger: Logger) -> dict[str, int | float]:
+def get_reversal_confirmation_config(config: Any, logger: Logger) -> dict[str, bool | int | float]:
     config = as_config_section(config, "reversal_confirmation", logger)
     validated = _validate_params(
         config,
@@ -1715,6 +1717,7 @@ def get_reversal_confirmation_config(config: Any, logger: Logger) -> dict[str, i
     )
 
     return {
+        "enabled": bool(validated["enabled"]),
         "lookback_period_candles": int(validated["lookback_period_candles"]),
         "decay_fraction": float(validated["decay_fraction"]),
         "min_natr_multiplier_fraction": float(min_natr_multiplier_fraction),