Indicators Reference
🤖 RussBot is a free, open-source binary options trading bot for PocketOption, built on BinaryOptionsToolsV2 → Get it on GitLab
💬 Need help? Join the Chipa Discord · ⚡ Go no-code with ChipaEditor
RussBot implements its three indicators from scratch in the TechnicalIndicators class — no TA library required. This page documents each implementation so you can verify, test, or modify them.
EMA — Exponential Moving Average
Used for: trend baseline (period 10) and as the building block for MACD.
The EMA seeds with an SMA over the first period values, then applies the standard recursive smoothing:
@staticmethod
def ema(data: List[float], period: int) -> List[float]:
"""Calculate Exponential Moving Average"""
if len(data) < period:
return [np.nan] * len(data)
ema_values = []
multiplier = 2 / (period + 1)
# Start with SMA for first value
sma = sum(data[:period]) / period
ema_values.extend([np.nan] * (period - 1))
ema_values.append(sma)
# Calculate EMA for remaining values
for i in range(period, len(data)):
ema = (data[i] * multiplier) + (ema_values[-1] * (1 - multiplier))
ema_values.append(ema)
return ema_values
Key properties:
- Returns
NaNfor the firstperiod - 1positions (not enough data) - Multiplier is
2 / (period + 1)— for EMA(10) that’s ≈ 0.1818, so each new close carries ~18% weight - In the strategy, the slope of the EMA (current vs. previous value) is as important as the price’s position relative to it
CCI — Commodity Channel Index
Used for: detecting momentum extremes at ±100 (period 7).
@staticmethod
def cci(high: List[float], low: List[float], close: List[float], period: int = 7) -> List[float]:
"""Calculate Commodity Channel Index"""
cci_values = []
for i in range(len(close)):
if i < period - 1:
cci_values.append(np.nan)
continue
# Typical price for each bar in the window
typical_prices = [
(high[j] + low[j] + close[j]) / 3
for j in range(i - period + 1, i + 1)
]
# SMA of typical price and mean absolute deviation
sma_tp = sum(typical_prices) / period
mad = sum(abs(tp - sma_tp) for tp in typical_prices) / period
# CCI formula (0.015 is Lambert's scaling constant)
current_tp = (high[i] + low[i] + close[i]) / 3
cci = (current_tp - sma_tp) / (0.015 * mad) if mad != 0 else 0
cci_values.append(cci)
return cci_values
Key properties:
- Typical price = (high + low + close) / 3
- The 0.015 constant scales CCI so ~70–80% of values fall between −100 and +100 — which is exactly why the strategy treats ±100 as “momentum extreme reached”
- Zero mean-deviation (a perfectly flat window) safely returns 0 instead of dividing by zero
- The short period (7) makes it responsive enough for 15-second candles
MACD — Moving Average Convergence Divergence
Used for: momentum context in the analysis output, and as the minimum-data gate (its 26-period slow EMA means the bot won’t trade until 26 candles exist).
@staticmethod
def macd(data: List[float], fast: int = 12, slow: int = 26, signal: int = 9):
"""Calculate MACD (line, signal, histogram)"""
ema_fast = TechnicalIndicators.ema(data, fast)
ema_slow = TechnicalIndicators.ema(data, slow)
# MACD line = fast EMA - slow EMA
macd_line = [
ema_fast[i] - ema_slow[i]
if not (pd.isna(ema_fast[i]) or pd.isna(ema_slow[i])) else np.nan
for i in range(len(data))
]
# Signal line = EMA(9) of the MACD line, computed on valid values only
# then mapped back to the full-length array
...
# Histogram = MACD line - signal line
histogram = [...]
return macd_line, signal_line, histogram
Key properties:
- The signal line is computed only on the non-NaN portion of the MACD line, then mapped back to full-length arrays — this avoids NaN contamination that naive implementations suffer from
- Returns three aligned lists: MACD line, signal line, histogram
- With defaults (12, 26, 9), the first valid signal value appears around candle 34
Data Requirements
| Indicator | First valid value at candle # |
|---|---|
| EMA(10) | 10 |
| CCI(7) | 7 |
| MACD line (12, 26) | 26 |
| MACD signal (9) | ~34 |
The bot’s calculate_indicators() requires at least 26 candles before returning anything, and the historical pre-load (1 hour via api.history()) means this is normally satisfied instantly at startup.
Verifying the Implementations
Run the bundled test script to check all three indicators against sample data — no PocketOption connection required:
python test_indicators.py
See Testing for details.
Customizing
All periods are configurable in config.json (ema_period, cci_period, macd_fast, macd_slow, macd_signal). If you swap in different indicators entirely, keep two things intact:
- The minimum-data gate — make sure
calculate_indicators()still refuses to run before your longest lookback is satisfied - The NaN discipline — return
Nonefromcalculate_indicators()whenever any current value is NaN, so the bot never trades on partial data
💡 Want to test indicator variations without touching the math? ChipaEditor lets you compose and backtest indicator-based strategies visually — and the Chipa Discord is the place to compare notes on what’s working.