Add fallback_reference for deviation when insufficient data points
Add optional min_data_points (default 100) and fallback_reference config fields to indicator definitions. When available daily data points are below min_data_points, the fallback_reference value is used as the deviation reference instead of the computed mean. Applied to ratio, price, spread, and diff_pct indicator types. Configured WTI/BRENT ratio with fallback_reference=0.96065.
This commit is contained in:
@ -62,14 +62,16 @@ Computes `numerator / denominator`.
|
||||
"numerator": "xyz:CL",
|
||||
"denominator": "xyz:BRENTOIL",
|
||||
"changes": ["1h", "1d"],
|
||||
"show_deviation": true
|
||||
"show_deviation": true,
|
||||
"min_data_points": 100,
|
||||
"fallback_reference": 0.96065
|
||||
}
|
||||
```
|
||||
|
||||
- **Value**: `live(numerator) / live(denominator)` from latest 1m candle closes
|
||||
- **1h Change**: compares to ratio from 1h candle close prices
|
||||
- **1D Change**: compares to ratio from 1d candle close prices
|
||||
- **Deviation**: `(current - long_avg) / long_avg * 100`, where `long_avg` is the mean of daily ratios over all available history
|
||||
- **Deviation**: `(current - long_avg) / long_avg * 100`, where `long_avg` is the mean of daily ratios over all available history. If fewer than `min_data_points` (default 100) daily data points exist and `fallback_reference` is set, the fallback value is used instead.
|
||||
|
||||
### `price` — Single Price
|
||||
|
||||
@ -190,7 +192,7 @@ All indicator calculations read from the SQLite database `_data/market_data.db`:
|
||||
- **Live value**: latest close price from `{coin}_1m` candle table (updated in real-time by `live_candle_fetcher.py`)
|
||||
- **1h change**: close price from `{coin}_1h` candle table (second-to-last completed 1h candle)
|
||||
- **1D change**: close price from `{coin}_1d` candle table (second-to-last completed 1d candle)
|
||||
- **Reference value**: mean of daily values over all available historical data
|
||||
- **Reference value**: mean of daily values over all available historical data. If fewer than `min_data_points` daily data points exist and `fallback_reference` is set, the fallback value is used instead.
|
||||
|
||||
## Process Architecture
|
||||
|
||||
@ -237,3 +239,12 @@ indicators_fetcher.py (subprocess, runs every 30s)
|
||||
2. Restart the application (`python main_app.py`). The Indicators Fetcher will automatically pick up the new config on its next run.
|
||||
|
||||
No code changes are needed for standard indicator types (`ratio`, `price`, `spread`, `diff_pct`, `ma`, `rsi`). For custom calculations, use the `custom` type.
|
||||
|
||||
### Optional Deviation Config Fields
|
||||
|
||||
The following optional fields control the deviation reference value:
|
||||
|
||||
| Field | Type | Default | Description |
|
||||
|-------|------|---------|-------------|
|
||||
| `min_data_points` | int | 100 | Minimum number of historical daily data points required before using the computed mean as the reference |
|
||||
| `fallback_reference` | float | null | If set and available data points are below `min_data_points`, this value is used as the reference instead of the computed mean |
|
||||
|
||||
12
_data/indicators.json
Normal file
12
_data/indicators.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"wti_brent_ratio": {
|
||||
"display_name": "WTI/BRENT",
|
||||
"type": "ratio",
|
||||
"numerator": "xyz:CL",
|
||||
"denominator": "xyz:BRENTOIL",
|
||||
"changes": ["1h", "1d"],
|
||||
"show_deviation": true,
|
||||
"min_data_points": 100,
|
||||
"fallback_reference": 0.96065
|
||||
}
|
||||
}
|
||||
@ -227,7 +227,12 @@ class IndicatorCalculator:
|
||||
if ind_def.get("show_deviation", False):
|
||||
ratios = self._get_all_ratio(num, den, "1d")
|
||||
if ratios:
|
||||
reference = sum(ratios) / len(ratios)
|
||||
min_points = ind_def.get("min_data_points", 100)
|
||||
fallback_ref = ind_def.get("fallback_reference")
|
||||
if len(ratios) < min_points and fallback_ref is not None:
|
||||
reference = fallback_ref
|
||||
else:
|
||||
reference = sum(ratios) / len(ratios)
|
||||
deviation = self._format_change(current, reference)
|
||||
|
||||
return {"value": current, "reference": reference, "changes": changes, "deviation": deviation}
|
||||
@ -250,7 +255,12 @@ class IndicatorCalculator:
|
||||
if ind_def.get("show_deviation", False):
|
||||
closes = self._get_all_closes(coin, "1d")
|
||||
if closes:
|
||||
reference = sum(closes) / len(closes)
|
||||
min_points = ind_def.get("min_data_points", 100)
|
||||
fallback_ref = ind_def.get("fallback_reference")
|
||||
if len(closes) < min_points and fallback_ref is not None:
|
||||
reference = fallback_ref
|
||||
else:
|
||||
reference = sum(closes) / len(closes)
|
||||
deviation = self._format_change(current, reference)
|
||||
|
||||
return {"value": current, "reference": reference, "changes": changes, "deviation": deviation}
|
||||
@ -281,7 +291,12 @@ class IndicatorCalculator:
|
||||
if ind_def.get("show_deviation", False):
|
||||
spreads = self._get_all_spread(num, den, "1d")
|
||||
if spreads:
|
||||
reference = sum(spreads) / len(spreads)
|
||||
min_points = ind_def.get("min_data_points", 100)
|
||||
fallback_ref = ind_def.get("fallback_reference")
|
||||
if len(spreads) < min_points and fallback_ref is not None:
|
||||
reference = fallback_ref
|
||||
else:
|
||||
reference = sum(spreads) / len(spreads)
|
||||
deviation = self._format_change(current, reference)
|
||||
|
||||
return {"value": current, "reference": reference, "changes": changes, "deviation": deviation}
|
||||
@ -312,7 +327,12 @@ class IndicatorCalculator:
|
||||
if ind_def.get("show_deviation", False):
|
||||
diffs = self._get_all_diff_pct(num, den, "1d")
|
||||
if diffs:
|
||||
reference = sum(diffs) / len(diffs)
|
||||
min_points = ind_def.get("min_data_points", 100)
|
||||
fallback_ref = ind_def.get("fallback_reference")
|
||||
if len(diffs) < min_points and fallback_ref is not None:
|
||||
reference = fallback_ref
|
||||
else:
|
||||
reference = sum(diffs) / len(diffs)
|
||||
deviation = self._format_change(current, reference)
|
||||
|
||||
return {"value": current, "reference": reference, "changes": changes, "deviation": deviation}
|
||||
|
||||
Reference in New Issue
Block a user