- Add `equal_division` (k/(n+1)) and `gann_octaves` (Gann octave/third levels closest to the full move, capped at nine) series; remove `pi_extensions` (near-entry bias, no trading basis).
- Rename `fibonacci_extensions` -> `fibonacci_retracements` (fractions are all < 1 = retracements, not extensions > 1); not backward compatible.
- Dispatch the series by `TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_SERIES[i]` index through a typed table (project enum-tuple convention).
- Bump version 3.13.2 -> 3.13.3.
},
{
"endCharacter": 98,
- "endLine": 1739,
+ "endLine": 1768,
"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": 1739
+ "startLine": 1768
},
{
"endCharacter": 33,
- "endLine": 1773,
+ "endLine": 1802,
"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": 1773
+ "startLine": 1802
},
{
"endCharacter": 33,
- "endLine": 1773,
+ "endLine": 1802,
"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": 1773
+ "startLine": 1802
},
{
"endCharacter": 23,
- "endLine": 1785,
+ "endLine": 1814,
"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": 1785
+ "startLine": 1814
},
{
"endCharacter": 83,
- "endLine": 2638,
+ "endLine": 2667,
"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": 2638
+ "startLine": 2667
},
{
"endCharacter": 38,
- "endLine": 3528,
+ "endLine": 3557,
"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": 3528
+ "startLine": 3557
},
{
"endCharacter": 34,
- "endLine": 3530,
+ "endLine": 3559,
"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": 3530
+ "startLine": 3559
},
{
"endCharacter": 55,
- "endLine": 3760,
+ "endLine": 3789,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"rolling\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 48,
- "startLine": 3760
+ "startLine": 3789
},
{
"endCharacter": 38,
- "endLine": 3785,
+ "endLine": 3814,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"rolling\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 31,
- "startLine": 3785
+ "startLine": 3814
},
{
"endCharacter": 55,
- "endLine": 3811,
+ "endLine": 3840,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"rolling\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 48,
- "startLine": 3811
+ "startLine": 3840
},
{
"endCharacter": 56,
- "endLine": 3812,
+ "endLine": 3841,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"rolling\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 49,
- "startLine": 3812
+ "startLine": 3841
},
{
"endCharacter": 33,
- "endLine": 3884,
+ "endLine": 3913,
"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": 3884
+ "startLine": 3913
},
{
"endCharacter": 69,
- "endLine": 3884,
+ "endLine": 3913,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "Expected 1 more positional argument",
"rule": "reportCallIssue",
"severity": "error",
"startCharacter": 59,
- "startLine": 3884
+ "startLine": 3913
},
{
"endCharacter": 40,
- "endLine": 3951,
+ "endLine": 3980,
"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": 3951
+ "startLine": 3980
},
{
"endCharacter": 38,
- "endLine": 3952,
+ "endLine": 3981,
"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": 3952
+ "startLine": 3981
},
{
"endCharacter": 42,
- "endLine": 3953,
+ "endLine": 3982,
"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": 3953
+ "startLine": 3982
},
{
"endCharacter": 45,
- "endLine": 3955,
+ "endLine": 3984,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"index\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 40,
- "startLine": 3955
+ "startLine": 3984
},
{
"endCharacter": 33,
- "endLine": 3957,
+ "endLine": 3986,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"iloc\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 29,
- "startLine": 3957
+ "startLine": 3986
},
{
"endCharacter": 31,
- "endLine": 3958,
+ "endLine": 3987,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"iloc\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 27,
- "startLine": 3958
+ "startLine": 3987
},
{
"endCharacter": 48,
- "endLine": 3963,
+ "endLine": 3992,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"index\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 43,
- "startLine": 3963
+ "startLine": 3992
},
{
"endCharacter": 40,
- "endLine": 3964,
+ "endLine": 3993,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"iloc\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 36,
- "startLine": 3964
+ "startLine": 3993
},
{
"endCharacter": 59,
- "endLine": 3966,
+ "endLine": 3995,
"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": 3966
+ "startLine": 3995
},
{
"endCharacter": 34,
- "endLine": 3968,
+ "endLine": 3997,
"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": 3968
+ "startLine": 3997
},
{
"endCharacter": 51,
- "endLine": 3968,
+ "endLine": 3997,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"iloc\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 47,
- "startLine": 3968
+ "startLine": 3997
},
{
"endCharacter": 72,
- "endLine": 3968,
+ "endLine": 3997,
"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": 3968
+ "startLine": 3997
},
{
"endCharacter": 40,
- "endLine": 4035,
+ "endLine": 4064,
"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": 4035
+ "startLine": 4064
},
{
"endCharacter": 33,
- "endLine": 4037,
+ "endLine": 4066,
"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": 4037
+ "startLine": 4066
},
{
"endCharacter": 35,
- "endLine": 4083,
+ "endLine": 4112,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"to_numpy\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 27,
- "startLine": 4083
+ "startLine": 4112
},
{
"endCharacter": 33,
- "endLine": 4084,
+ "endLine": 4113,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"to_numpy\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 25,
- "startLine": 4084
+ "startLine": 4113
},
{
"endCharacter": 37,
- "endLine": 4201,
+ "endLine": 4230,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"to_numpy\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 29,
- "startLine": 4201
+ "startLine": 4230
},
{
"endCharacter": 35,
- "endLine": 4202,
+ "endLine": 4231,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"to_numpy\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 27,
- "startLine": 4202
+ "startLine": 4231
},
{
"endCharacter": 33,
- "endLine": 4203,
+ "endLine": 4232,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"to_numpy\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 25,
- "startLine": 4203
+ "startLine": 4232
},
{
"endCharacter": 39,
- "endLine": 4223,
+ "endLine": 4252,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"to_numpy\" is not a known attribute of \"None\"",
"rule": "reportOptionalMemberAccess",
"severity": "error",
"startCharacter": 31,
- "startLine": 4223
+ "startLine": 4252
},
{
"endCharacter": 92,
- "endLine": 4582,
+ "endLine": 4611,
"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": 4582
+ "startLine": 4611
},
{
"endCharacter": 85,
- "endLine": 4983,
+ "endLine": 5012,
"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": 4983
+ "startLine": 5012
},
{
"endCharacter": 29,
- "endLine": 5026,
+ "endLine": 5055,
"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": 5026
+ "startLine": 5055
},
{
"endCharacter": 43,
- "endLine": 5027,
+ "endLine": 5056,
"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": 5027
+ "startLine": 5056
},
{
"endCharacter": 62,
- "endLine": 5030,
+ "endLine": 5059,
"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": 5030
+ "startLine": 5059
},
{
"endCharacter": 35,
- "endLine": 5052,
+ "endLine": 5081,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "Object of type \"None\" is not subscriptable",
"rule": "reportOptionalSubscript",
"severity": "error",
"startCharacter": 27,
- "startLine": 5052
+ "startLine": 5081
},
{
"endCharacter": 35,
- "endLine": 5098,
+ "endLine": 5127,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "Object of type \"None\" is not subscriptable",
"rule": "reportOptionalSubscript",
"severity": "error",
"startCharacter": 27,
- "startLine": 5098
+ "startLine": 5127
},
{
"endCharacter": 49,
- "endLine": 5168,
+ "endLine": 5197,
"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": 5168
+ "startLine": 5197
},
{
"endCharacter": 75,
- "endLine": 5411,
+ "endLine": 5440,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "Operator \"<=\" not supported for \"None\"",
"rule": "reportOptionalOperand",
"severity": "error",
"startCharacter": 54,
- "startLine": 5411
+ "startLine": 5440
},
{
"endCharacter": 23,
- "endLine": 5574,
+ "endLine": 5603,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"best_params\" is possibly unbound",
"rule": "reportPossiblyUnboundVariable",
"severity": "error",
"startCharacter": 12,
- "startLine": 5574
+ "startLine": 5603
},
{
"endCharacter": 38,
- "endLine": 5581,
+ "endLine": 5610,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"best_params\" is possibly unbound",
"rule": "reportPossiblyUnboundVariable",
"severity": "error",
"startCharacter": 27,
- "startLine": 5581
+ "startLine": 5610
},
{
"endCharacter": 22,
- "endLine": 5593,
+ "endLine": 5622,
"file": "quickadapter/user_data/strategies/Utils.py",
"message": "\"best_params\" is possibly unbound",
"rule": "reportPossiblyUnboundVariable",
"severity": "error",
"startCharacter": 11,
- "startLine": 5593
+ "startLine": 5622
},
{
"endCharacter": 22,
- "endLine": 5751,
+ "endLine": 5780,
"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": 5751
+ "startLine": 5780
},
{
"endCharacter": 14,
- "endLine": 5787,
+ "endLine": 5816,
"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": 5787
+ "startLine": 5816
},
{
"endCharacter": 22,
- "endLine": 5871,
+ "endLine": 5900,
"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": 5871
+ "startLine": 5900
},
{
"endCharacter": 14,
- "endLine": 5905,
+ "endLine": 5934,
"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": 5905
+ "startLine": 5934
},
{
"endCharacter": 22,
- "endLine": 5976,
+ "endLine": 6005,
"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": 5976
+ "startLine": 6005
},
{
"endCharacter": 22,
- "endLine": 6077,
+ "endLine": 6106,
"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": 6077
+ "startLine": 6106
},
{
"endCharacter": 26,
- "endLine": 6160,
+ "endLine": 6189,
"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": 6160
+ "startLine": 6189
}
],
"filesAnalyzed": 6,
### Exit pricing
-| Path | Runtime fallback | Type / Range | Description |
-| -------------------------------------------------------------- | ---------------------- | ------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
-| exit_pricing.trade_natr_method | `moving_average` | enum {`moving_average`,`quantile_interpolation`,`weighted_average`} | Trade NATR (Normalized Average True Range) aggregation for stoploss and take-profit distances. `moving_average` uses KAMA to preserve nonnegative volatility. The stoploss never loosens, including after partial exits, and remains unchanged on order fills. |
-| exit_pricing.final_take_profit_retracement_fraction | 0.375 | float (0,1] | Fraction of the final take-profit target distance used as the frozen trailing retracement distance after the final target arms the exit. The final exit tracks the best subsequent per-candle rate and exits only after this material adverse move; elapsed stagnation alone does not exit. Plot annotations show only the current trail boundary from the candle that established it; earlier boundaries are not retained. |
-| exit_pricing.take_profit_stage_natr_multiplier_fraction_series | `fibonacci_extensions` | enum {`fibonacci_extensions`,`pi_extensions`} | With the default four rungs, partial target distances are approximately 23.6%, 38.2% and 61.8% of the full target distance for `fibonacci_extensions`, or 3.2%, 10.1% and 31.8% for `pi_extensions`. Pi places partial targets closer to entry. Partial fractions are recomputed when the rung count changes; the final rung always uses the full distance. This setting changes target distances only, not nominal stake shares; execution constraints are described in the decision cycle. Invalid values use the default. |
+| Path | Runtime fallback | Type / Range | Description |
+| -------------------------------------------------------------- | ------------------------ | ------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
+| exit_pricing.trade_natr_method | `moving_average` | enum {`moving_average`,`quantile_interpolation`,`weighted_average`} | Trade NATR (Normalized Average True Range) aggregation for stoploss and take-profit distances. `moving_average` uses KAMA to preserve nonnegative volatility. The stoploss never loosens, including after partial exits, and remains unchanged on order fills. |
+| exit_pricing.final_take_profit_retracement_fraction | 0.375 | float (0,1] | Fraction of the final take-profit target distance used as the frozen trailing retracement distance after the final target arms the exit. The final exit tracks the best subsequent per-candle rate and exits only after this material adverse move; elapsed stagnation alone does not exit. Plot annotations show only the current trail boundary from the candle that established it; earlier boundaries are not retained. |
+| exit_pricing.take_profit_stage_natr_multiplier_fraction_series | `fibonacci_retracements` | enum {`fibonacci_retracements`,`equal_division`,`gann_octaves`} | Each series places the partial rungs as fractions of the full target distance. `fibonacci_retracements` uses Fibonacci retracement ratios (default three partial rungs: ~23.6%, 38.2% and 61.8%). `equal_division` spaces the rungs evenly (default three partial rungs: 25%, 50% and 75%). `gann_octaves` uses the Gann octave and third levels closest to the full move (default three partial rungs: ~66.7%, 75% and 87.5%) and supports at most nine partial rungs. Partial fractions are recomputed when the rung count changes; the final rung always uses the full distance. This setting changes target distances only, not nominal stake shares; execution constraints are described in the decision cycle. Invalid values use the default. |
### Reversal confirmation
self.assertEqual(model.get_exit_stage_natr_multiplier_fraction(99), 1.0)
self.assertEqual(model.get_exit_stage_natr_multiplier_fraction(-1), 1.0)
- def test_the_fibonacci_extensions_define_the_default_ladder(self):
+ def test_the_fibonacci_retracements_define_the_default_ladder(self):
# Frozen reference rungs, not a restatement of the formula: a change of
# base or of the stage count must fail here. Three partial rungs are
# phi**-3, phi**-2 and phi**-1, then the full distance.
def test_the_ladder_is_indexed_by_the_stage_count(self):
self.assertEqual(
- len(get_take_profit_stage_natr_multiplier_fractions("fibonacci_extensions", 0)), 0
+ len(get_take_profit_stage_natr_multiplier_fractions("fibonacci_retracements", 0)), 0
)
for count in (1, 2, 3, 4, 5):
with self.subTest(count=count):
fractions = get_take_profit_stage_natr_multiplier_fractions(
- "fibonacci_extensions", count
+ "fibonacci_retracements", count
)
self.assertEqual(len(fractions), count)
self.assertEqual(max(fractions), fractions[-1])
- def test_the_pi_extensions_define_the_ladder(self):
+ def test_the_equal_division_defines_the_default_rung_count_ladder(self):
+ # Evenly spaced rungs: with the default three partial rungs, k / 4 for
+ # k in 1..3, then the full distance.
assert_allclose(
tuple(
strategy(
- fraction_series="pi_extensions"
+ fraction_series="equal_division"
).exit_stage_natr_multiplier_fractions.values()
),
- (0.03225153, 0.10132118, 0.31830989, 1.0),
- rtol=1e-6,
+ (0.25, 0.5, 0.75, 1.0),
+ rtol=1e-12,
+ )
+
+ def test_the_gann_octaves_define_the_default_rung_count_ladder(self):
+ # Gann levels closest to the full move: with the default three partial
+ # rungs, 2/3, 3/4 and 7/8, then the full distance.
+ assert_allclose(
+ tuple(
+ strategy(
+ fraction_series="gann_octaves"
+ ).exit_stage_natr_multiplier_fractions.values()
+ ),
+ (2.0 / 3.0, 0.75, 0.875, 1.0),
+ rtol=1e-12,
)
+ def test_gann_octaves_refuses_more_rungs_than_it_defines(self):
+ # Gann defines nine sub-move levels; a tenth partial rung is refused.
+ self.assertEqual(len(get_take_profit_stage_natr_multiplier_fractions("gann_octaves", 9)), 9)
+ with self.assertRaises(ValueError):
+ get_take_profit_stage_natr_multiplier_fractions("gann_octaves", 10)
+
def test_selecting_a_series_changes_the_stage_distances(self):
frame = candles([100.0, 100.0, 100.0], natr=[1.0, 4.0, 8.0], multiplier=MULTIPLIER)
long_trade = trade()
- fibonacci = strategy(fraction_series="fibonacci_extensions")
- pi = strategy(fraction_series="pi_extensions")
- self.assertEqual(pi.take_profit_stage_natr_multiplier_fraction_series, "pi_extensions")
+ fibonacci = strategy(fraction_series="fibonacci_retracements")
+ equal = strategy(fraction_series="equal_division")
+ self.assertEqual(equal.take_profit_stage_natr_multiplier_fraction_series, "equal_division")
partial_stages = list(QuickAdapterV3.partial_exit_stages())
- for stage in partial_stages:
- with self.subTest(stage=stage):
- fibonacci_distance = fibonacci.get_take_profit_target(frame, long_trade, stage)[1]
- pi_distance = pi.get_take_profit_target(frame, long_trade, stage)[1]
- # The larger pi extension base yields smaller reciprocal fractions.
- self.assertLess(pi_distance, fibonacci_distance)
- # The final distance is independent of the partial extension series.
+ fibonacci_distances = [
+ fibonacci.get_take_profit_target(frame, long_trade, stage)[1]
+ for stage in partial_stages
+ ]
+ equal_distances = [
+ equal.get_take_profit_target(frame, long_trade, stage)[1] for stage in partial_stages
+ ]
+ # Distinct series price the partial rungs at distinct distances.
+ self.assertNotEqual(fibonacci_distances, equal_distances)
+ # The final distance is independent of the partial series.
self.assertEqual(
fibonacci.get_take_profit_target(frame, long_trade, QuickAdapterV3.final_exit_stage()),
- pi.get_take_profit_target(frame, long_trade, QuickAdapterV3.final_exit_stage()),
+ equal.get_take_profit_target(frame, long_trade, QuickAdapterV3.final_exit_stage()),
)
def test_fraction_series_validates_names_and_stage_counts(self):
with self.assertRaises(ValueError):
get_take_profit_stage_natr_multiplier_fractions("not_a_series", 3)
self.assertEqual(
- get_take_profit_stage_natr_multiplier_fractions("fibonacci_extensions", 0), ()
+ get_take_profit_stage_natr_multiplier_fractions("fibonacci_retracements", 0), ()
)
assert_allclose(
- get_take_profit_stage_natr_multiplier_fractions("fibonacci_extensions", 1),
+ get_take_profit_stage_natr_multiplier_fractions("fibonacci_retracements", 1),
(0.618033988749895,),
rtol=1e-14,
)
- def test_a_degenerate_ladder_base_is_refused_by_name(self):
- from Utils import _TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_BASES
-
- for name, base in (("zero", 0.0), ("unit", 1.0), ("near", 1.0 + 2**-52)):
- with self.subTest(base=base):
- _TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_BASES[name] = base
- self.addCleanup(_TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_BASES.pop, name, None)
- self.addCleanup(get_take_profit_stage_natr_multiplier_fractions.cache_clear)
- with self.assertRaises(ValueError) as raised:
- get_take_profit_stage_natr_multiplier_fractions(name, 3)
- self.assertIn(name, str(raised.exception))
-
def test_an_underflowing_ladder_is_refused(self):
- # pi**-650 is the smallest positive subnormal; pi**-651 underflows to 0.0.
- fractions = get_take_profit_stage_natr_multiplier_fractions("pi_extensions", 650)
- self.assertEqual(len(fractions), 650)
- self.assertEqual(fractions[0], math.ulp(0.0))
+ # For a large enough rung count the geometric rungs underflow to zero;
+ # the first such count is refused, one rung short nothing underflows.
+ base = (1.0 + math.sqrt(5.0)) / 2.0
+ underflowing = next(k for k in range(1, 10000) if base**-k <= 0.0)
+ fractions = get_take_profit_stage_natr_multiplier_fractions(
+ "fibonacci_retracements", underflowing - 1
+ )
+ self.assertEqual(len(fractions), underflowing - 1)
+ self.assertGreater(fractions[0], 0.0)
with self.assertRaises(ValueError):
- get_take_profit_stage_natr_multiplier_fractions("pi_extensions", 651)
+ get_take_profit_stage_natr_multiplier_fractions("fibonacci_retracements", underflowing)
def test_a_negative_partial_stage_count_is_rejected(self):
with self.assertRaises(ValueError):
- get_take_profit_stage_natr_multiplier_fractions("fibonacci_extensions", -1)
+ get_take_profit_stage_natr_multiplier_fractions("fibonacci_retracements", -1)
def test_the_remaining_stake_share_grows_with_the_stage_index(self):
# Shares apply to the stake still open, so each rung closes a larger
DEFAULTS_CUSTOM_PROTECTIONS,
DEFAULTS_EXIT_PRICING,
DEFAULTS_REVERSAL_CONFIRMATION,
+ TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_SERIES,
get_causal_mode,
get_custom_protections_config,
get_exit_pricing_config,
self.assertEqual([logging.WARNING], [record.levelno for record in captured.records])
def test_exit_pricing_every_supported_fraction_series_is_preserved(self) -> None:
- for series in ("fibonacci_extensions", "pi_extensions"):
+ for series in TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_SERIES:
with self.subTest(series=series):
with recorded_warnings() as (logger, sink):
resolved = get_exit_pricing_config(
https://github.com/sponsors/robcaulk
"""
- version = "3.13.2"
+ version = "3.13.3"
_CALIBRATION_START_KEY: Final[str] = "quickadapter_calibration_start"
_DEPLOYMENT_COORDINATE_MARKER_KEY: Final[str] = "quickadapter_deployment_coordinates"
_ANNOTATION_LINE_OFFSET_CANDLES: Final[int] = 10
def version(self) -> str:
- return "3.13.2"
+ return "3.13.3"
timeframe = "5m"
timeframe_minutes = timeframe_to_minutes(timeframe)
def exit_stage_natr_multiplier_fractions(self) -> dict[int, float]:
"""Target distance of each stage as a fraction of the full distance.
- Partial rungs follow the configured reciprocal-extension series; the
+ Partial rungs follow the configured fraction series; the
final rung sits at the full distance.
"""
partial_stages = QuickAdapterV3.partial_exit_stages()
)
-TakeProfitStageNatrMultiplierFractionSeries = Literal["fibonacci_extensions", "pi_extensions"]
+TakeProfitStageNatrMultiplierFractionSeries = Literal[
+ "fibonacci_retracements",
+ "equal_division",
+ "gann_octaves",
+]
TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_SERIES: Final[
tuple[TakeProfitStageNatrMultiplierFractionSeries, ...]
] = (
- "fibonacci_extensions",
- "pi_extensions",
+ "fibonacci_retracements",
+ "equal_division",
+ "gann_octaves",
)
-# Extension bases: stage ``k`` of ``n`` uses the reciprocal of ``base ** (n - k)``.
-# These fractions place partial targets inside the full take-profit distance;
-# they do not extend it. Fibonacci uses integer powers of phi; pi uses integer
-# powers of pi as a custom geometric construction, not a trading convention.
-# The strategy appends the final fraction ``1.0`` to the generated
-# partial-target distance ladder.
-_TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_BASES: Final[dict[str, float]] = {
- "fibonacci_extensions": (1.0 + math.sqrt(5.0)) / 2.0,
- "pi_extensions": math.pi,
-}
+# Series place partial targets strictly inside the full take-profit distance.
+# The strategy appends the independent final fraction
+# ``1.0`` to the generated partial-target ladder. Each series is dispatched by
+# its index into TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_SERIES.
+# The Fibonacci retracement base (the golden ratio): the closest partial
+# fraction is 1 / base = 0.618, at most 2/3, keeping rungs inside the move.
+_FIBONACCI_RETRACEMENT_BASE: Final[float] = (1.0 + math.sqrt(5.0)) / 2.0
+# Gann octave (``i / 8``) and third (``1/3``, ``2/3``) levels strictly inside the
+# full move, ascending; the series takes the levels closest to the full distance,
+# so it defines at most nine partial rungs.
+_GANN_OCTAVE_LEVELS: Final[tuple[float, ...]] = tuple(
+ sorted([i / 8.0 for i in range(1, 8)] + [1.0 / 3.0, 2.0 / 3.0])
+)
+
+
+def _fibonacci_retracement_stage_fractions(partial_stage_count: int) -> tuple[float, ...]:
+ """Stage ``k`` of ``n`` uses 1 / base ** (n - k), i.e. the ``n`` largest
+ reciprocal powers of the golden ratio; the first three are the canonical
+ Fibonacci retracement ratios (0.618, 0.382, 0.236)."""
+ base = _FIBONACCI_RETRACEMENT_BASE
+ return tuple(base ** -(partial_stage_count - stage) for stage in range(partial_stage_count))
-# The closest partial fraction is 1 / base; a 1.5 floor keeps it at most 2/3.
-# This relative gap does not guarantee distinct prices after rounding.
-_TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_MIN_BASE: Final[float] = 1.5
+
+def _equal_division_stage_fractions(partial_stage_count: int) -> tuple[float, ...]:
+ """``n`` equal spacings across the full move: k / (n + 1) for k in 1..n."""
+ return tuple((stage + 1) / (partial_stage_count + 1) for stage in range(partial_stage_count))
+
+
+def _gann_octaves_stage_fractions(partial_stage_count: int) -> tuple[float, ...]:
+ """The ``n`` Gann octave/third levels closest to the full move (at most nine)."""
+ if partial_stage_count > len(_GANN_OCTAVE_LEVELS):
+ raise ValueError(
+ f"Invalid partial_stage_count value {partial_stage_count}: "
+ f"series {TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_SERIES[2]!r} "
+ f"defines {len(_GANN_OCTAVE_LEVELS)} rungs"
+ )
+ return _GANN_OCTAVE_LEVELS[-partial_stage_count:] if partial_stage_count else ()
@lru_cache(maxsize=_CACHE_MAXSIZE_SMALL)
def get_take_profit_stage_natr_multiplier_fractions(
series: str, partial_stage_count: int
) -> tuple[float, ...]:
- """Return ascending reciprocal-extension fractions for partial take-profit targets.
+ """Return ascending fractions of the full take-profit distance for partial targets.
- Stage ``k`` of ``n`` uses ``1 / base ** (n - k)``. Each fraction scales
- the full take-profit distance and remains strictly below the independent
- final fraction ``1.0``.
+ Each series places its ``partial_stage_count`` rungs strictly inside the full
+ distance; the strategy appends the independent final fraction ``1.0``.
"""
- base = _TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_BASES.get(series)
- if base is None:
+ if partial_stage_count < 0:
+ raise ValueError(f"Invalid partial_stage_count value {partial_stage_count}: must be >= 0")
+ stage_fractions: dict[str, Callable[[int], tuple[float, ...]]] = {
+ # 0 - "fibonacci_retracements"
+ TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_SERIES[
+ 0
+ ]: _fibonacci_retracement_stage_fractions,
+ # 1 - "equal_division"
+ TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_SERIES[1]: _equal_division_stage_fractions,
+ # 2 - "gann_octaves"
+ TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_SERIES[2]: _gann_octaves_stage_fractions,
+ }
+ handler = stage_fractions.get(series)
+ if handler is None:
raise ValueError(
enum_error_message(
"take_profit_stage_natr_multiplier_fraction_series",
TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_SERIES,
)
)
- if partial_stage_count < 0:
- raise ValueError(f"Invalid partial_stage_count value {partial_stage_count}: must be >= 0")
- if base < _TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_MIN_BASE:
- raise ValueError(
- f"Invalid base value {base!r} for series {series!r}: "
- f"must be >= {_TAKE_PROFIT_STAGE_NATR_MULTIPLIER_FRACTION_MIN_BASE}"
- )
-
- fractions = tuple(
- base ** -(partial_stage_count - stage) for stage in range(partial_stage_count)
- )
+ fractions = handler(partial_stage_count)
if any(fraction <= 0.0 for fraction in fractions):
- # Only reachable by denormal underflow: the base floor above guarantees
- # ``base > 1``, so no rung can reach or exceed ``1.0``.
+ # Defensive: an unbounded rung count can underflow a rung to zero
+ # (fibonacci_retracements, where base ** -(n-k) underflows to zero at n = 1549).
raise ValueError(
f"Invalid partial_stage_count value {partial_stage_count!r} for series {series!r}: "
"NATR multiplier fractions must be > 0 (underflow to zero)"