mirror of
https://github.com/jpawlowski/hass.tibber_prices.git
synced 2026-03-30 13:23:41 +00:00
refactor(config): optimize volatility thresholds with separate ranges and improved UX
Volatility Threshold Optimization: - Replaced global MIN/MAX_VOLATILITY_THRESHOLD (0-100%) with six separate constants for overlapping ranges per threshold level - MODERATE: 5.0-25.0% (was: 0-100%) - HIGH: 20.0-40.0% (was: 0-100%) - VERY_HIGH: 35.0-80.0% (was: 0-100%) - Added detailed comments explaining ranges and cascading requirements Validators: - Added three specific validation functions (one per threshold level) - Added cross-validation ensuring MODERATE < HIGH < VERY_HIGH - Added fallback to existing option values for completeness check - Updated error keys to specific messages per threshold level UI Improvements: - Changed NumberSelector mode: BOX → SLIDER (consistency with other config steps) - Changed step size: 0.1% → 1.0% (better UX, sufficient precision) - Updated min/max ranges to match new validation constants Translations: - Removed: "invalid_volatility_threshold" (generic) - Added: "invalid_volatility_threshold_moderate/high/very_high" (specific ranges) - Added: "invalid_volatility_thresholds" (cross-validation error) - Updated all 5 languages (de, en, nb, nl, sv) Files modified: - config_flow_handlers/options_flow.py: Updated validation logic - config_flow_handlers/schemas.py: Updated NumberSelector configs - config_flow_handlers/validators.py: Added specific validators + cross-validation - const.py: Replaced global constants with six specific constants - translations/*.json: Updated error messages (5 languages) Impact: Users get clearer validation errors with specific ranges shown, better UX with sliders and appropriate step size, and guaranteed threshold ordering (MODERATE < HIGH < VERY_HIGH).
This commit is contained in:
parent
0fd98554ae
commit
14b68a504b
9 changed files with 151 additions and 35 deletions
|
|
@ -29,7 +29,10 @@ from custom_components.tibber_prices.config_flow_handlers.validators import (
|
||||||
validate_price_trend_falling,
|
validate_price_trend_falling,
|
||||||
validate_price_trend_rising,
|
validate_price_trend_rising,
|
||||||
validate_relaxation_attempts,
|
validate_relaxation_attempts,
|
||||||
validate_volatility_threshold,
|
validate_volatility_threshold_high,
|
||||||
|
validate_volatility_threshold_moderate,
|
||||||
|
validate_volatility_threshold_very_high,
|
||||||
|
validate_volatility_thresholds,
|
||||||
)
|
)
|
||||||
from custom_components.tibber_prices.const import (
|
from custom_components.tibber_prices.const import (
|
||||||
CONF_BEST_PRICE_FLEX,
|
CONF_BEST_PRICE_FLEX,
|
||||||
|
|
@ -51,6 +54,9 @@ from custom_components.tibber_prices.const import (
|
||||||
CONF_VOLATILITY_THRESHOLD_HIGH,
|
CONF_VOLATILITY_THRESHOLD_HIGH,
|
||||||
CONF_VOLATILITY_THRESHOLD_MODERATE,
|
CONF_VOLATILITY_THRESHOLD_MODERATE,
|
||||||
CONF_VOLATILITY_THRESHOLD_VERY_HIGH,
|
CONF_VOLATILITY_THRESHOLD_VERY_HIGH,
|
||||||
|
DEFAULT_VOLATILITY_THRESHOLD_HIGH,
|
||||||
|
DEFAULT_VOLATILITY_THRESHOLD_MODERATE,
|
||||||
|
DEFAULT_VOLATILITY_THRESHOLD_VERY_HIGH,
|
||||||
DOMAIN,
|
DOMAIN,
|
||||||
)
|
)
|
||||||
from homeassistant.config_entries import ConfigFlowResult, OptionsFlow
|
from homeassistant.config_entries import ConfigFlowResult, OptionsFlow
|
||||||
|
|
@ -359,22 +365,41 @@ class TibberPricesOptionsFlowHandler(OptionsFlow):
|
||||||
|
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
# Validate moderate volatility threshold
|
# Validate moderate volatility threshold
|
||||||
if CONF_VOLATILITY_THRESHOLD_MODERATE in user_input and not validate_volatility_threshold(
|
if CONF_VOLATILITY_THRESHOLD_MODERATE in user_input and not validate_volatility_threshold_moderate(
|
||||||
user_input[CONF_VOLATILITY_THRESHOLD_MODERATE]
|
user_input[CONF_VOLATILITY_THRESHOLD_MODERATE]
|
||||||
):
|
):
|
||||||
errors[CONF_VOLATILITY_THRESHOLD_MODERATE] = "invalid_volatility_threshold"
|
errors[CONF_VOLATILITY_THRESHOLD_MODERATE] = "invalid_volatility_threshold_moderate"
|
||||||
|
|
||||||
# Validate high volatility threshold
|
# Validate high volatility threshold
|
||||||
if CONF_VOLATILITY_THRESHOLD_HIGH in user_input and not validate_volatility_threshold(
|
if CONF_VOLATILITY_THRESHOLD_HIGH in user_input and not validate_volatility_threshold_high(
|
||||||
user_input[CONF_VOLATILITY_THRESHOLD_HIGH]
|
user_input[CONF_VOLATILITY_THRESHOLD_HIGH]
|
||||||
):
|
):
|
||||||
errors[CONF_VOLATILITY_THRESHOLD_HIGH] = "invalid_volatility_threshold"
|
errors[CONF_VOLATILITY_THRESHOLD_HIGH] = "invalid_volatility_threshold_high"
|
||||||
|
|
||||||
# Validate very high volatility threshold
|
# Validate very high volatility threshold
|
||||||
if CONF_VOLATILITY_THRESHOLD_VERY_HIGH in user_input and not validate_volatility_threshold(
|
if CONF_VOLATILITY_THRESHOLD_VERY_HIGH in user_input and not validate_volatility_threshold_very_high(
|
||||||
user_input[CONF_VOLATILITY_THRESHOLD_VERY_HIGH]
|
user_input[CONF_VOLATILITY_THRESHOLD_VERY_HIGH]
|
||||||
):
|
):
|
||||||
errors[CONF_VOLATILITY_THRESHOLD_VERY_HIGH] = "invalid_volatility_threshold"
|
errors[CONF_VOLATILITY_THRESHOLD_VERY_HIGH] = "invalid_volatility_threshold_very_high"
|
||||||
|
|
||||||
|
# Cross-validation: Ensure MODERATE < HIGH < VERY_HIGH
|
||||||
|
if not errors:
|
||||||
|
existing_options = self.config_entry.options
|
||||||
|
moderate = user_input.get(
|
||||||
|
CONF_VOLATILITY_THRESHOLD_MODERATE,
|
||||||
|
existing_options.get(CONF_VOLATILITY_THRESHOLD_MODERATE, DEFAULT_VOLATILITY_THRESHOLD_MODERATE),
|
||||||
|
)
|
||||||
|
high = user_input.get(
|
||||||
|
CONF_VOLATILITY_THRESHOLD_HIGH,
|
||||||
|
existing_options.get(CONF_VOLATILITY_THRESHOLD_HIGH, DEFAULT_VOLATILITY_THRESHOLD_HIGH),
|
||||||
|
)
|
||||||
|
very_high = user_input.get(
|
||||||
|
CONF_VOLATILITY_THRESHOLD_VERY_HIGH,
|
||||||
|
existing_options.get(CONF_VOLATILITY_THRESHOLD_VERY_HIGH, DEFAULT_VOLATILITY_THRESHOLD_VERY_HIGH),
|
||||||
|
)
|
||||||
|
|
||||||
|
if not validate_volatility_thresholds(moderate, high, very_high):
|
||||||
|
errors["base"] = "invalid_volatility_thresholds"
|
||||||
|
|
||||||
if not errors:
|
if not errors:
|
||||||
self._options.update(user_input)
|
self._options.update(user_input)
|
||||||
|
|
|
||||||
|
|
@ -67,7 +67,9 @@ from custom_components.tibber_prices.const import (
|
||||||
MAX_PRICE_TREND_FALLING,
|
MAX_PRICE_TREND_FALLING,
|
||||||
MAX_PRICE_TREND_RISING,
|
MAX_PRICE_TREND_RISING,
|
||||||
MAX_RELAXATION_ATTEMPTS,
|
MAX_RELAXATION_ATTEMPTS,
|
||||||
MAX_VOLATILITY_THRESHOLD,
|
MAX_VOLATILITY_THRESHOLD_HIGH,
|
||||||
|
MAX_VOLATILITY_THRESHOLD_MODERATE,
|
||||||
|
MAX_VOLATILITY_THRESHOLD_VERY_HIGH,
|
||||||
MIN_GAP_COUNT,
|
MIN_GAP_COUNT,
|
||||||
MIN_PERIOD_LENGTH,
|
MIN_PERIOD_LENGTH,
|
||||||
MIN_PRICE_RATING_THRESHOLD_HIGH,
|
MIN_PRICE_RATING_THRESHOLD_HIGH,
|
||||||
|
|
@ -75,7 +77,9 @@ from custom_components.tibber_prices.const import (
|
||||||
MIN_PRICE_TREND_FALLING,
|
MIN_PRICE_TREND_FALLING,
|
||||||
MIN_PRICE_TREND_RISING,
|
MIN_PRICE_TREND_RISING,
|
||||||
MIN_RELAXATION_ATTEMPTS,
|
MIN_RELAXATION_ATTEMPTS,
|
||||||
MIN_VOLATILITY_THRESHOLD,
|
MIN_VOLATILITY_THRESHOLD_HIGH,
|
||||||
|
MIN_VOLATILITY_THRESHOLD_MODERATE,
|
||||||
|
MIN_VOLATILITY_THRESHOLD_VERY_HIGH,
|
||||||
PEAK_PRICE_MIN_LEVEL_OPTIONS,
|
PEAK_PRICE_MIN_LEVEL_OPTIONS,
|
||||||
)
|
)
|
||||||
from homeassistant.const import CONF_ACCESS_TOKEN
|
from homeassistant.const import CONF_ACCESS_TOKEN
|
||||||
|
|
@ -215,11 +219,11 @@ def get_volatility_schema(options: Mapping[str, Any]) -> vol.Schema:
|
||||||
),
|
),
|
||||||
): NumberSelector(
|
): NumberSelector(
|
||||||
NumberSelectorConfig(
|
NumberSelectorConfig(
|
||||||
min=MIN_VOLATILITY_THRESHOLD,
|
min=MIN_VOLATILITY_THRESHOLD_MODERATE,
|
||||||
max=MAX_VOLATILITY_THRESHOLD,
|
max=MAX_VOLATILITY_THRESHOLD_MODERATE,
|
||||||
step=0.1,
|
step=1.0,
|
||||||
unit_of_measurement="%",
|
unit_of_measurement="%",
|
||||||
mode=NumberSelectorMode.BOX,
|
mode=NumberSelectorMode.SLIDER,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
vol.Optional(
|
vol.Optional(
|
||||||
|
|
@ -232,11 +236,11 @@ def get_volatility_schema(options: Mapping[str, Any]) -> vol.Schema:
|
||||||
),
|
),
|
||||||
): NumberSelector(
|
): NumberSelector(
|
||||||
NumberSelectorConfig(
|
NumberSelectorConfig(
|
||||||
min=MIN_VOLATILITY_THRESHOLD,
|
min=MIN_VOLATILITY_THRESHOLD_HIGH,
|
||||||
max=MAX_VOLATILITY_THRESHOLD,
|
max=MAX_VOLATILITY_THRESHOLD_HIGH,
|
||||||
step=0.1,
|
step=1.0,
|
||||||
unit_of_measurement="%",
|
unit_of_measurement="%",
|
||||||
mode=NumberSelectorMode.BOX,
|
mode=NumberSelectorMode.SLIDER,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
vol.Optional(
|
vol.Optional(
|
||||||
|
|
@ -249,11 +253,11 @@ def get_volatility_schema(options: Mapping[str, Any]) -> vol.Schema:
|
||||||
),
|
),
|
||||||
): NumberSelector(
|
): NumberSelector(
|
||||||
NumberSelectorConfig(
|
NumberSelectorConfig(
|
||||||
min=MIN_VOLATILITY_THRESHOLD,
|
min=MIN_VOLATILITY_THRESHOLD_VERY_HIGH,
|
||||||
max=MAX_VOLATILITY_THRESHOLD,
|
max=MAX_VOLATILITY_THRESHOLD_VERY_HIGH,
|
||||||
step=0.1,
|
step=1.0,
|
||||||
unit_of_measurement="%",
|
unit_of_measurement="%",
|
||||||
mode=NumberSelectorMode.BOX,
|
mode=NumberSelectorMode.SLIDER,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,9 @@ from custom_components.tibber_prices.const import (
|
||||||
MAX_PRICE_TREND_FALLING,
|
MAX_PRICE_TREND_FALLING,
|
||||||
MAX_PRICE_TREND_RISING,
|
MAX_PRICE_TREND_RISING,
|
||||||
MAX_RELAXATION_ATTEMPTS,
|
MAX_RELAXATION_ATTEMPTS,
|
||||||
MAX_VOLATILITY_THRESHOLD,
|
MAX_VOLATILITY_THRESHOLD_HIGH,
|
||||||
|
MAX_VOLATILITY_THRESHOLD_MODERATE,
|
||||||
|
MAX_VOLATILITY_THRESHOLD_VERY_HIGH,
|
||||||
MIN_GAP_COUNT,
|
MIN_GAP_COUNT,
|
||||||
MIN_PERIOD_LENGTH,
|
MIN_PERIOD_LENGTH,
|
||||||
MIN_PRICE_RATING_THRESHOLD_HIGH,
|
MIN_PRICE_RATING_THRESHOLD_HIGH,
|
||||||
|
|
@ -29,7 +31,9 @@ from custom_components.tibber_prices.const import (
|
||||||
MIN_PRICE_TREND_FALLING,
|
MIN_PRICE_TREND_FALLING,
|
||||||
MIN_PRICE_TREND_RISING,
|
MIN_PRICE_TREND_RISING,
|
||||||
MIN_RELAXATION_ATTEMPTS,
|
MIN_RELAXATION_ATTEMPTS,
|
||||||
MIN_VOLATILITY_THRESHOLD,
|
MIN_VOLATILITY_THRESHOLD_HIGH,
|
||||||
|
MIN_VOLATILITY_THRESHOLD_MODERATE,
|
||||||
|
MIN_VOLATILITY_THRESHOLD_VERY_HIGH,
|
||||||
)
|
)
|
||||||
from homeassistant.exceptions import HomeAssistantError
|
from homeassistant.exceptions import HomeAssistantError
|
||||||
from homeassistant.helpers.aiohttp_client import async_create_clientsession
|
from homeassistant.helpers.aiohttp_client import async_create_clientsession
|
||||||
|
|
@ -219,18 +223,78 @@ def validate_price_rating_thresholds(threshold_low: int, threshold_high: int) ->
|
||||||
return threshold_low < threshold_high
|
return threshold_low < threshold_high
|
||||||
|
|
||||||
|
|
||||||
def validate_volatility_threshold(threshold: float) -> bool:
|
def validate_volatility_threshold_moderate(threshold: float) -> bool:
|
||||||
"""
|
"""
|
||||||
Validate volatility threshold percentage.
|
Validate moderate volatility threshold.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
threshold: Volatility threshold percentage (0.0 to 100.0)
|
threshold: Moderate volatility threshold percentage (5.0 to 25.0)
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
True if threshold is valid (MIN_VOLATILITY_THRESHOLD to MAX_VOLATILITY_THRESHOLD)
|
True if threshold is valid (MIN_VOLATILITY_THRESHOLD_MODERATE to MAX_VOLATILITY_THRESHOLD_MODERATE)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
return MIN_VOLATILITY_THRESHOLD <= threshold <= MAX_VOLATILITY_THRESHOLD
|
return MIN_VOLATILITY_THRESHOLD_MODERATE <= threshold <= MAX_VOLATILITY_THRESHOLD_MODERATE
|
||||||
|
|
||||||
|
|
||||||
|
def validate_volatility_threshold_high(threshold: float) -> bool:
|
||||||
|
"""
|
||||||
|
Validate high volatility threshold.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
threshold: High volatility threshold percentage (20.0 to 40.0)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if threshold is valid (MIN_VOLATILITY_THRESHOLD_HIGH to MAX_VOLATILITY_THRESHOLD_HIGH)
|
||||||
|
|
||||||
|
"""
|
||||||
|
return MIN_VOLATILITY_THRESHOLD_HIGH <= threshold <= MAX_VOLATILITY_THRESHOLD_HIGH
|
||||||
|
|
||||||
|
|
||||||
|
def validate_volatility_threshold_very_high(threshold: float) -> bool:
|
||||||
|
"""
|
||||||
|
Validate very high volatility threshold.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
threshold: Very high volatility threshold percentage (35.0 to 80.0)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if threshold is valid (MIN_VOLATILITY_THRESHOLD_VERY_HIGH to MAX_VOLATILITY_THRESHOLD_VERY_HIGH)
|
||||||
|
|
||||||
|
"""
|
||||||
|
return MIN_VOLATILITY_THRESHOLD_VERY_HIGH <= threshold <= MAX_VOLATILITY_THRESHOLD_VERY_HIGH
|
||||||
|
|
||||||
|
|
||||||
|
def validate_volatility_thresholds(
|
||||||
|
threshold_moderate: float,
|
||||||
|
threshold_high: float,
|
||||||
|
threshold_very_high: float,
|
||||||
|
) -> bool:
|
||||||
|
"""
|
||||||
|
Cross-validate all three volatility thresholds together.
|
||||||
|
|
||||||
|
Ensures that MODERATE < HIGH < VERY_HIGH to maintain logical classification
|
||||||
|
boundaries. Each threshold represents an escalating level of price volatility.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
threshold_moderate: Moderate volatility threshold (5.0 to 25.0)
|
||||||
|
threshold_high: High volatility threshold (20.0 to 40.0)
|
||||||
|
threshold_very_high: Very high volatility threshold (35.0 to 80.0)
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True if all thresholds are valid individually AND maintain proper ordering
|
||||||
|
|
||||||
|
"""
|
||||||
|
# Validate individual ranges first
|
||||||
|
if not validate_volatility_threshold_moderate(threshold_moderate):
|
||||||
|
return False
|
||||||
|
if not validate_volatility_threshold_high(threshold_high):
|
||||||
|
return False
|
||||||
|
if not validate_volatility_threshold_very_high(threshold_very_high):
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Ensure cascading order: MODERATE < HIGH < VERY_HIGH
|
||||||
|
return threshold_moderate < threshold_high < threshold_very_high
|
||||||
|
|
||||||
|
|
||||||
def validate_price_trend_rising(threshold: int) -> bool:
|
def validate_price_trend_rising(threshold: int) -> bool:
|
||||||
|
|
|
||||||
|
|
@ -112,8 +112,16 @@ MIN_PRICE_RATING_THRESHOLD_HIGH = 5 # Minimum value for high rating threshold (
|
||||||
MAX_PRICE_RATING_THRESHOLD_HIGH = 50 # Maximum value for high rating threshold
|
MAX_PRICE_RATING_THRESHOLD_HIGH = 50 # Maximum value for high rating threshold
|
||||||
|
|
||||||
# Volatility threshold limits
|
# Volatility threshold limits
|
||||||
MIN_VOLATILITY_THRESHOLD = 0.0 # Minimum volatility threshold percentage
|
# MODERATE threshold: practical range 5% to 25% (entry point for noticeable fluctuation)
|
||||||
MAX_VOLATILITY_THRESHOLD = 100.0 # Maximum volatility threshold percentage
|
# HIGH threshold: practical range 20% to 40% (significant price swings)
|
||||||
|
# VERY_HIGH threshold: practical range 35% to 80% (extreme volatility)
|
||||||
|
# Ensure cascading: MODERATE < HIGH < VERY_HIGH with ~5% minimum gaps
|
||||||
|
MIN_VOLATILITY_THRESHOLD_MODERATE = 5.0 # Minimum for moderate volatility threshold
|
||||||
|
MAX_VOLATILITY_THRESHOLD_MODERATE = 25.0 # Maximum for moderate volatility threshold (must be < HIGH)
|
||||||
|
MIN_VOLATILITY_THRESHOLD_HIGH = 20.0 # Minimum for high volatility threshold (must be > MODERATE)
|
||||||
|
MAX_VOLATILITY_THRESHOLD_HIGH = 40.0 # Maximum for high volatility threshold (must be < VERY_HIGH)
|
||||||
|
MIN_VOLATILITY_THRESHOLD_VERY_HIGH = 35.0 # Minimum for very high volatility threshold (must be > HIGH)
|
||||||
|
MAX_VOLATILITY_THRESHOLD_VERY_HIGH = 80.0 # Maximum for very high volatility threshold
|
||||||
|
|
||||||
# Price trend threshold limits
|
# Price trend threshold limits
|
||||||
MIN_PRICE_TREND_RISING = 1 # Minimum rising trend threshold
|
MIN_PRICE_TREND_RISING = 1 # Minimum rising trend threshold
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,10 @@
|
||||||
"invalid_price_rating_low": "Untere Preis-Bewertungsschwelle muss zwischen -50% und -5% liegen",
|
"invalid_price_rating_low": "Untere Preis-Bewertungsschwelle muss zwischen -50% und -5% liegen",
|
||||||
"invalid_price_rating_high": "Obere Preis-Bewertungsschwelle muss zwischen 5% und 50% liegen",
|
"invalid_price_rating_high": "Obere Preis-Bewertungsschwelle muss zwischen 5% und 50% liegen",
|
||||||
"invalid_price_rating_thresholds": "Untere Schwelle muss kleiner als obere Schwelle sein",
|
"invalid_price_rating_thresholds": "Untere Schwelle muss kleiner als obere Schwelle sein",
|
||||||
"invalid_volatility_threshold": "Volatilitätsschwelle muss zwischen 0% und 100% liegen",
|
"invalid_volatility_threshold_moderate": "Moderate Volatilitätsschwelle muss zwischen 5% und 25% liegen",
|
||||||
|
"invalid_volatility_threshold_high": "Hohe Volatilitätsschwelle muss zwischen 20% und 40% liegen",
|
||||||
|
"invalid_volatility_threshold_very_high": "Sehr hohe Volatilitätsschwelle muss zwischen 35% und 80% liegen",
|
||||||
|
"invalid_volatility_thresholds": "Schwellenwerte müssen aufsteigend sein: moderat < hoch < sehr hoch",
|
||||||
"invalid_price_trend_rising": "Steigender Trendschwellenwert muss zwischen 1% und 50% liegen",
|
"invalid_price_trend_rising": "Steigender Trendschwellenwert muss zwischen 1% und 50% liegen",
|
||||||
"invalid_price_trend_falling": "Fallender Trendschwellenwert muss zwischen -50% und -1% liegen"
|
"invalid_price_trend_falling": "Fallender Trendschwellenwert muss zwischen -50% und -1% liegen"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,10 @@
|
||||||
"invalid_price_rating_low": "Low price rating threshold must be between -50% and -5%",
|
"invalid_price_rating_low": "Low price rating threshold must be between -50% and -5%",
|
||||||
"invalid_price_rating_high": "High price rating threshold must be between 5% and 50%",
|
"invalid_price_rating_high": "High price rating threshold must be between 5% and 50%",
|
||||||
"invalid_price_rating_thresholds": "Low threshold must be less than high threshold",
|
"invalid_price_rating_thresholds": "Low threshold must be less than high threshold",
|
||||||
"invalid_volatility_threshold": "Volatility threshold must be between 0% and 100%",
|
"invalid_volatility_threshold_moderate": "Moderate volatility threshold must be between 5% and 25%",
|
||||||
|
"invalid_volatility_threshold_high": "High volatility threshold must be between 20% and 40%",
|
||||||
|
"invalid_volatility_threshold_very_high": "Very high volatility threshold must be between 35% and 80%",
|
||||||
|
"invalid_volatility_thresholds": "Thresholds must be in ascending order: moderate < high < very high",
|
||||||
"invalid_price_trend_rising": "Rising trend threshold must be between 1% and 50%",
|
"invalid_price_trend_rising": "Rising trend threshold must be between 1% and 50%",
|
||||||
"invalid_price_trend_falling": "Falling trend threshold must be between -50% and -1%"
|
"invalid_price_trend_falling": "Falling trend threshold must be between -50% and -1%"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,10 @@
|
||||||
"invalid_price_rating_low": "Lav prisvurderingsgrense må være mellom -50% og -5%",
|
"invalid_price_rating_low": "Lav prisvurderingsgrense må være mellom -50% og -5%",
|
||||||
"invalid_price_rating_high": "Høy prisvurderingsgrense må være mellom 5% og 50%",
|
"invalid_price_rating_high": "Høy prisvurderingsgrense må være mellom 5% og 50%",
|
||||||
"invalid_price_rating_thresholds": "Lav grense må være mindre enn høy grense",
|
"invalid_price_rating_thresholds": "Lav grense må være mindre enn høy grense",
|
||||||
"invalid_volatility_threshold": "Volatilitetsgrense må være mellom 0% og 100%",
|
"invalid_volatility_threshold_moderate": "Moderat volatilitetsgrense må være mellom 5% og 25%",
|
||||||
|
"invalid_volatility_threshold_high": "Høy volatilitetsgrense må være mellom 20% og 40%",
|
||||||
|
"invalid_volatility_threshold_very_high": "Svært høy volatilitetsgrense må være mellom 35% og 80%",
|
||||||
|
"invalid_volatility_thresholds": "Grensene må være i stigende rekkefølge: moderat < høy < svært høy",
|
||||||
"invalid_price_trend_rising": "Stigende trendgrense må være mellom 1% og 50%",
|
"invalid_price_trend_rising": "Stigende trendgrense må være mellom 1% og 50%",
|
||||||
"invalid_price_trend_falling": "Fallende trendgrense må være mellom -50% og -1%"
|
"invalid_price_trend_falling": "Fallende trendgrense må være mellom -50% og -1%"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,10 @@
|
||||||
"invalid_price_rating_low": "Lage prijsbeoordelingsdrempel moet tussen -50% en -5% liggen",
|
"invalid_price_rating_low": "Lage prijsbeoordelingsdrempel moet tussen -50% en -5% liggen",
|
||||||
"invalid_price_rating_high": "Hoge prijsbeoordelingsdrempel moet tussen 5% en 50% liggen",
|
"invalid_price_rating_high": "Hoge prijsbeoordelingsdrempel moet tussen 5% en 50% liggen",
|
||||||
"invalid_price_rating_thresholds": "Lage drempel moet lager zijn dan hoge drempel",
|
"invalid_price_rating_thresholds": "Lage drempel moet lager zijn dan hoge drempel",
|
||||||
"invalid_volatility_threshold": "Volatiliteitsdrempel moet tussen 0% en 100% liggen",
|
"invalid_volatility_threshold_moderate": "Gematigde volatiliteitsdrempel moet tussen 5% en 25% liggen",
|
||||||
|
"invalid_volatility_threshold_high": "Hoge volatiliteitsdrempel moet tussen 20% en 40% liggen",
|
||||||
|
"invalid_volatility_threshold_very_high": "Zeer hoge volatiliteitsdrempel moet tussen 35% en 80% liggen",
|
||||||
|
"invalid_volatility_thresholds": "Drempels moeten in oplopende volgorde zijn: gematigd < hoog < zeer hoog",
|
||||||
"invalid_price_trend_rising": "Stijgende trenddrempel moet tussen 1% en 50% liggen",
|
"invalid_price_trend_rising": "Stijgende trenddrempel moet tussen 1% en 50% liggen",
|
||||||
"invalid_price_trend_falling": "Dalende trenddrempel moet tussen -50% en -1% liggen"
|
"invalid_price_trend_falling": "Dalende trenddrempel moet tussen -50% en -1% liggen"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -207,7 +207,10 @@
|
||||||
"invalid_price_rating_low": "Låg prisklassificeringströskel måste vara mellan -50% och -5%",
|
"invalid_price_rating_low": "Låg prisklassificeringströskel måste vara mellan -50% och -5%",
|
||||||
"invalid_price_rating_high": "Hög prisklassificeringströskel måste vara mellan 5% och 50%",
|
"invalid_price_rating_high": "Hög prisklassificeringströskel måste vara mellan 5% och 50%",
|
||||||
"invalid_price_rating_thresholds": "Låg tröskel måste vara mindre än hög tröskel",
|
"invalid_price_rating_thresholds": "Låg tröskel måste vara mindre än hög tröskel",
|
||||||
"invalid_volatility_threshold": "Volatilitetströskel måste vara mellan 0% och 100%",
|
"invalid_volatility_threshold_moderate": "Måttlig volatilitetströskel måste vara mellan 5% och 25%",
|
||||||
|
"invalid_volatility_threshold_high": "Hög volatilitetströskel måste vara mellan 20% och 40%",
|
||||||
|
"invalid_volatility_threshold_very_high": "Mycket hög volatilitetströskel måste vara mellan 35% och 80%",
|
||||||
|
"invalid_volatility_thresholds": "Trösklar måste vara i stigande ordning: måttlig < hög < mycket hög",
|
||||||
"invalid_price_trend_rising": "Stigande trendtröskel måste vara mellan 1% och 50%",
|
"invalid_price_trend_rising": "Stigande trendtröskel måste vara mellan 1% och 50%",
|
||||||
"invalid_price_trend_falling": "Fallande trendtröskel måste vara mellan -50% och -1%"
|
"invalid_price_trend_falling": "Fallande trendtröskel måste vara mellan -50% och -1%"
|
||||||
},
|
},
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue