self,
df: DataFrame,
pair: str,
- side: str,
- order: Literal["entry", "exit"],
+ side: TradeDirection,
+ order: OrderType,
rate: float,
lookback_period: int,
decay_ratio: float,
Rejection Conditions
--------------------
- Empty dataframe, invalid side/order, negative lookback, decay_ratio outside (0,1],
- failure to break current threshold, or failed historical step comparison.
+ Empty dataframe, invalid side/order, non-finite rate, negative lookback,
+ decay_ratio outside (0,1], invalid min/max ordering, failure to break current
+ threshold, or failed historical step comparison.
Complexity
----------
Limitations
-----------
- No validation of min/max ordering beyond usage; no strict mode; partial data may
- still confirm. Rate finiteness not explicitly validated.
+ No strict mode; partial data may still confirm.
"""
if df.empty:
return False
return False
if order not in QuickAdapterV3._order_types_set():
return False
+ if not isinstance(rate, (int, float)) or not np.isfinite(rate):
+ return False
+ if (
+ not isinstance(min_natr_ratio_percent, (int, float))
+ or not isinstance(max_natr_ratio_percent, (int, float))
+ or not np.isfinite(min_natr_ratio_percent)
+ or not np.isfinite(max_natr_ratio_percent)
+ or min_natr_ratio_percent < 0
+ or max_natr_ratio_percent < 0
+ or min_natr_ratio_percent > max_natr_ratio_percent
+ ):
+ return False
trade_direction = side
import talib.abstract as ta
from numpy.typing import NDArray
from scipy.ndimage import gaussian_filter1d
-from scipy.stats import gmean
+from scipy.stats import gmean, percentileofscore
from technical import qtpylib
T = TypeVar("T", pd.Series, float)
def calculate_quantile(values: NDArray[np.floating], value: float) -> float:
+ """Return the quantile (0-1) of value within values.
+
+ Uses percentileofscore(kind='mean') for unbiased estimation.
+ Returns np.nan if values is empty. NaN values are ignored.
+ """
if values.size == 0:
return np.nan
- first_value = values[0]
- if np.allclose(values, first_value):
- return (
- 0.5
- if np.isclose(value, first_value)
- else (0.0 if value < first_value else 1.0)
- )
-
- return np.sum(values <= value) / values.size
+ return percentileofscore(values, value, kind="mean", nan_policy="omit") / 100.0
class TrendDirection(IntEnum):