From: Jérôme Benoit Date: Thu, 5 Nov 2026 00:29:11 +0000 (+0100) Subject: feat(quickadapter): add entry reversal toggle (#305) X-Git-Url: https://git.piment-noir.org/?a=commitdiff_plain;h=0243d1c316899c882184f0425b1922d58e462e86;p=freqai-strategies.git feat(quickadapter): add entry reversal toggle (#305) * 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 --- diff --git a/quickadapter/.basedpyright/diagnostics.json b/quickadapter/.basedpyright/diagnostics.json index efa25c4..144f8a6 100644 --- a/quickadapter/.basedpyright/diagnostics.json +++ b/quickadapter/.basedpyright/diagnostics.json @@ -833,293 +833,283 @@ }, { "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, @@ -1171,405 +1161,415 @@ "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, @@ -1603,523 +1603,523 @@ }, { "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, diff --git a/quickadapter/README.md b/quickadapter/README.md index 05e7ced..d031bd1 100644 --- a/quickadapter/README.md +++ b/quickadapter/README.md @@ -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 diff --git a/quickadapter/tests/test_strategy_sizing.py b/quickadapter/tests/test_strategy_sizing.py index 1aa9129..c232a2a 100644 --- a/quickadapter/tests/test_strategy_sizing.py +++ b/quickadapter/tests/test_strategy_sizing.py @@ -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() diff --git a/quickadapter/tests/test_utils_config_resolution.py b/quickadapter/tests/test_utils_config_resolution.py index 3addb11..1cf9dfb 100644 --- a/quickadapter/tests/test_utils_config_resolution.py +++ b/quickadapter/tests/test_utils_config_resolution.py @@ -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( diff --git a/quickadapter/user_data/config-template.json b/quickadapter/user_data/config-template.json index def7731..e8d8b56 100644 --- a/quickadapter/user_data/config-template.json +++ b/quickadapter/user_data/config-template.json @@ -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 }, diff --git a/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py b/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py index 29389d4..e1eded5 100644 --- a/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py +++ b/quickadapter/user_data/freqaimodels/QuickAdapterRegressorV3.py @@ -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" diff --git a/quickadapter/user_data/strategies/QuickAdapterV3.py b/quickadapter/user_data/strategies/QuickAdapterV3.py index 348d068..8989f01 100644 --- a/quickadapter/user_data/strategies/QuickAdapterV3.py +++ b/quickadapter/user_data/strategies/QuickAdapterV3.py @@ -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, diff --git a/quickadapter/user_data/strategies/Utils.py b/quickadapter/user_data/strategies/Utils.py index ec39343..3cd60a2 100644 --- a/quickadapter/user_data/strategies/Utils.py +++ b/quickadapter/user_data/strategies/Utils.py @@ -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),